优化我的存储过程 - 这是正确的方法吗?
Optimizing my stored procedure - is this the right way to do it?
SELECT TOP 1 @CurrentStudentID = StudentID
FROM Courses WITH (NOLOCK)
WHERE Courses.CourseID = @CourseID
ORDER BY StudentID
-- Loop through all the students and find if he/she is registered for more than one course.
WHILE (@@ROWCOUNT > 0 AND @CurrentStudentID IS NOT NULL)
BEGIN
-- Select all other courses student is currently registered in.
IF @@ROWCOUNT > 0
BEGIN
-- return required information
END
ELSE
BEGIN
-- Perform some operations
END
-- Select the next registered student
SELECT TOP 1 @CurrentStudentID = StudentID
FROM Courses WITH (NOLOCK)
WHERE Courses.CourseID = @CourseID AND
Courses.StudentID > @CurrentStudentID
ORDER BY StudentID
END
有人可以帮我解释一下这里的逻辑吗?我写了一个存储过程来查明某门课程的学生目前是否正在上同一所学校的其他课程。
如果学生人数众多,我特别担心两个 SELECT 查询和 while 循环的性能。我觉得我这样做的方式感觉很做作。我相信有更好的方法可以做到这一点。
我已经对此存储过程进行了 SQL 分析,单个调用的持续时间范围为 0 - 60 毫秒。我不明白为什么同一个存储过程的执行时间如此随机和不一致。
感谢任何帮助。我只有 1 年以上的 SQL Server 2008 经验。
提前致谢。
正如我提到的,SQL 是一种基于集合的理论语言。换句话说,它与数据集是半相关的,允许在数据组之间进行有效比较。 "Lower" 语言,如 C++ 或 Java 不维护这么大的数据集,因为它们是基于游标(逐行)的语言。
这个定义是高层次的,重点是将您的数据想象成 EXCEL
表。您有预定义的列,例如 CourseID
和 StudentID
,它们在其他列中具有依赖于这些值的信息 (CourseID
1:1 Course_Name) 和一些重复的信息(CourseID 可以有多个学生)。
真正的规范化包括删除相互依赖的列,但现在不用担心。主要关注点是什么对业务有意义。您的 table 有其课程和学生的识别列。因此,如果这些值没有冲突的相互依存值,则不需要使用游标。
SELECT StudentID, COUNT(COURSEID) AS CLASS_NUM
FROM COURSES
GROUP BY StudentID
HAVING COUNT(COURSEID) > 1
GROUP BY
returns 列中不同的值集,将其他行展平并允许像 COUNT()
这样的聚合函数。 (注意:NULLS
不计入 COUNT()
。使用 ISNULL
函数)
您尚未限制列表,但您获得了相同的结果。在 SQL 展平行之后,如果需要,您可以使用 HAVING
子句进一步限制来自 GROUP BY
的结果集。
绝对比游标快得多。 :)
现在,如果您的 table 包括不同学期和年级的学生,您可以考虑将其添加到 GROUP BY
,这样您的 GROUP BY
中就有了集合(StudentID
和 Year
)
此外,回想一下 SELECT
语句在逻辑上在 GROUP BY
和 HAVING
子句之后读取,因此 SELECT
语句中列出的任何列都必须出现在 GROUP BY
或者有聚合函数。
SELECT TOP 1 @CurrentStudentID = StudentID
FROM Courses WITH (NOLOCK)
WHERE Courses.CourseID = @CourseID
ORDER BY StudentID
-- Loop through all the students and find if he/she is registered for more than one course.
WHILE (@@ROWCOUNT > 0 AND @CurrentStudentID IS NOT NULL)
BEGIN
-- Select all other courses student is currently registered in.
IF @@ROWCOUNT > 0
BEGIN
-- return required information
END
ELSE
BEGIN
-- Perform some operations
END
-- Select the next registered student
SELECT TOP 1 @CurrentStudentID = StudentID
FROM Courses WITH (NOLOCK)
WHERE Courses.CourseID = @CourseID AND
Courses.StudentID > @CurrentStudentID
ORDER BY StudentID
END
有人可以帮我解释一下这里的逻辑吗?我写了一个存储过程来查明某门课程的学生目前是否正在上同一所学校的其他课程。
如果学生人数众多,我特别担心两个 SELECT 查询和 while 循环的性能。我觉得我这样做的方式感觉很做作。我相信有更好的方法可以做到这一点。
我已经对此存储过程进行了 SQL 分析,单个调用的持续时间范围为 0 - 60 毫秒。我不明白为什么同一个存储过程的执行时间如此随机和不一致。
感谢任何帮助。我只有 1 年以上的 SQL Server 2008 经验。
提前致谢。
正如我提到的,SQL 是一种基于集合的理论语言。换句话说,它与数据集是半相关的,允许在数据组之间进行有效比较。 "Lower" 语言,如 C++ 或 Java 不维护这么大的数据集,因为它们是基于游标(逐行)的语言。
这个定义是高层次的,重点是将您的数据想象成 EXCEL
表。您有预定义的列,例如 CourseID
和 StudentID
,它们在其他列中具有依赖于这些值的信息 (CourseID
1:1 Course_Name) 和一些重复的信息(CourseID 可以有多个学生)。
真正的规范化包括删除相互依赖的列,但现在不用担心。主要关注点是什么对业务有意义。您的 table 有其课程和学生的识别列。因此,如果这些值没有冲突的相互依存值,则不需要使用游标。
SELECT StudentID, COUNT(COURSEID) AS CLASS_NUM
FROM COURSES
GROUP BY StudentID
HAVING COUNT(COURSEID) > 1
GROUP BY
returns 列中不同的值集,将其他行展平并允许像 COUNT()
这样的聚合函数。 (注意:NULLS
不计入 COUNT()
。使用 ISNULL
函数)
您尚未限制列表,但您获得了相同的结果。在 SQL 展平行之后,如果需要,您可以使用 HAVING
子句进一步限制来自 GROUP BY
的结果集。
绝对比游标快得多。 :)
现在,如果您的 table 包括不同学期和年级的学生,您可以考虑将其添加到 GROUP BY
,这样您的 GROUP BY
中就有了集合(StudentID
和 Year
)
此外,回想一下 SELECT
语句在逻辑上在 GROUP BY
和 HAVING
子句之后读取,因此 SELECT
语句中列出的任何列都必须出现在 GROUP BY
或者有聚合函数。