使连接条件更加独占导致查询挂起

时间:2011-06-01 22:59:34

标签: sql sql-server tsql

对不起SQL的问题,但我在下面的查询中遇到了一些问题。它似乎永远不会完成执行(它运行几分钟,然后我杀了它)。奇怪的是,如果我将StudentTestsPre表的连接条件从 TestInstances.fkSchoolYearID =(TestInstancesPre.fkSchoolYearID + 1)更改为 TestInstances.fkSchoolYearID> TestInstancesPre.fkSchoolYearID ,然后查询立即返回。如何使用更独特的连接条件导致我的查询挂起?似乎这样可以使查询更快,如果有的话。

有什么想法吗?

            SELECT *
        FROM TestInstances
        INNER JOIN StudentTests on StudentTests.fkTestInstanceID = TestInstances.pkTestInstanceID
                                    AND StudentTests.pkStudentTestID IN (SELECT * FROM @tempTests)
        INNER JOIN TestInstances TestInstancesPre ON TestInstances.fkSchoolYearID = (TestInstancesPre.fkSchoolYearID + 1)
                                        AND TestInstancesPre.fkTestTypeID = 1 AND TestInstances.fkTestTypeID = 1
        INNER JOIN StudentTests StudentTestsPre on StudentTestsPre.fkTestInstanceID = TestInstancesPre.pkTestInstanceID
                                        AND StudentTests.fkStudentID = StudentTestsPre.fkStudentID
        INNER JOIN StudentScores_Subject s ON s.fkStudentTestID = StudentTests.pkStudentTestID
                                        AND s.fkTest_SubjectID IN (SELECT pkTestSubjectID FROM MM_Test_Subjects WHERE fkCSTStrandID IN (SELECT number FROM itot(@strAcceptableStrands, N','))  AND fkTestTypeID = 1)
                                        AND s.fkScoreTypeID = 3
        INNER JOIN StudentScores_Subject sPre ON sPre.fkStudentTestID = StudentTestsPre.pkStudentTestID
                                        AND sPre.fkTest_SubjectID IN (SELECT pkTestSubjectID FROM MM_Test_Subjects WHERE fkCSTStrandID IN (SELECT number FROM itot(@strAcceptableStrands, N','))  AND fkTestTypeID = 1)
                                        AND sPre.fkScoreTypeID = 3
        INNER JOIN MM_Test_PL_SS_Ranges r ON r.fkTest_SubjectID = s.fkTest_SubjectID 
                                        AND r.fkSchoolYearID = TestInstances.fkSchoolYearID 
                                        AND r.fkTestTypeID = TestInstances.fkTestTypeID
                                        AND (r.fkGradeID = StudentTests.fkGradeID OR r.fkGradeID = 99)
        INNER JOIN MM_Test_PL_SS_Ranges rPre ON rPre.fkTest_SubjectID = sPre.fkTest_SubjectID 
                                        AND rPre.fkSchoolYearID = TestInstancesPre.fkSchoolYearID 
                                        AND rPre.fkTestTypeID = TestInstancesPre.fkTestTypeID
                                        AND (rPre.fkGradeID = StudentTestsPre.fkGradeID OR rPre.fkGradeID = 99)
        INNER JOIN StudentScores_Subject s2 ON s2.fkStudentTestID = StudentTests.pkStudentTestID
                                        AND s2.fkTest_SubjectID = s.fkTest_SubjectID
                                        AND s2.fkScoreTypeID = 2
        INNER JOIN StudentScores_Subject sPre2 ON sPre2.fkStudentTestID = StudentTestsPre.pkStudentTestID
                                        AND sPre2.fkTest_SubjectID = sPre.fkTest_SubjectID
                                        AND sPre2.fkScoreTypeID = 2
        INNER JOIN Students on Students.pkStudentID = StudentTests.fkStudentID

感谢您的帮助!


对于SO,这是上面的脚本与替代格式&短别名:

SELECT *
FROM TestInstances

  INNER JOIN StudentTests st
     ON st.fkTestInstanceID = ti.pkTestInstanceID
    AND st.pkStudentTestID IN (SELECT * FROM @tempTests)

  INNER JOIN TestInstances tiPre
     ON ti.fkSchoolYearID = (tiPre.fkSchoolYearID + 1)
    AND tiPre.fkTestTypeID = 1 AND ti.fkTestTypeID = 1

  INNER JOIN StudentTests stPre
     ON stPre.fkTestInstanceID = tiPre.pkTestInstanceID
    AND st.fkStudentID = stPre.fkStudentID

  INNER JOIN StudentScores_Subject s
     ON s.fkStudentTestID = st.pkStudentTestID
    AND s.fkTest_SubjectID IN (
          SELECT pkTestSubjectID
          FROM MM_Test_Subjects
          WHERE fkCSTStrandID IN (
                  SELECT number FROM itot(@strAcceptableStrands, N','))
            AND fkTestTypeID = 1)
    AND s.fkScoreTypeID = 3

  INNER JOIN StudentScores_Subject sPre
     ON sPre.fkStudentTestID = stPre.pkStudentTestID
    AND sPre.fkTest_SubjectID IN (
          SELECT pkTestSubjectID
          FROM MM_Test_Subjects
          WHERE fkCSTStrandID IN (
                  SELECT number FROM itot(@strAcceptableStrands, N','))
            AND fkTestTypeID = 1)
    AND sPre.fkScoreTypeID = 3

  INNER JOIN MM_Test_PL_SS_Ranges r
     ON r.fkTest_SubjectID = s.fkTest_SubjectID 
    AND r.fkSchoolYearID = ti.fkSchoolYearID 
    AND r.fkTestTypeID = ti.fkTestTypeID
    AND (r.fkGradeID = st.fkGradeID OR r.fkGradeID = 99)

  INNER JOIN MM_Test_PL_SS_Ranges rPre
     ON rPre.fkTest_SubjectID = sPre.fkTest_SubjectID 
    AND rPre.fkSchoolYearID = tiPre.fkSchoolYearID 
    AND rPre.fkTestTypeID = tiPre.fkTestTypeID
    AND (rPre.fkGradeID = stPre.fkGradeID OR rPre.fkGradeID = 99)

  INNER JOIN StudentScores_Subject s2
     ON s2.fkStudentTestID = st.pkStudentTestID
    AND s2.fkTest_SubjectID = s.fkTest_SubjectID
    AND s2.fkScoreTypeID = 2

  INNER JOIN StudentScores_Subject sPre2
     ON sPre2.fkStudentTestID = stPre.pkStudentTestID
    AND sPre2.fkTest_SubjectID = sPre.fkTest_SubjectID
    AND sPre2.fkScoreTypeID = 2

  INNER JOIN Students
     ON Students.pkStudentID = st.fkStudentID

2 个答案:

答案 0 :(得分:4)

看看你的执行计划。我的猜测是,在连接又名(TestInstancesPre.fkSchoolYearID + 1)中进行计算会导致索引无法正确使用。一种简单的测试方法是将您的联接更改为:

TestInstances.fkSchoolYearID = TestInstancesPre.fkSchoolYearID 

在连接中做一些时髦的东西时,我看到性能下降了。比如:

ON t1.column1 = ISNULL(t2.myColumn, 1) 

我相信这是因为查询变得不可思议。有关详细信息,请查看this SO post

答案 1 :(得分:0)

通过比较计算,它可以使索引的使用无效。当计算结果的数据类型与要编制索引的列的数据类型不同时,通常会发生这种情况。如果必须重复足够次数(例如,来自大量连接),有时计算成本很高。一种解决方案是将计算值存储在特殊列中,例如:

CREATE TABLE TestInstances (
...
nextSchoolYearID int);

使用触发器或逻辑来维护nextSchoolYearID = fkSchoolYearID + 1,然后使用

ON TestInstances.fkSchoolYearID = TestInstancesPre.nextSchoolYearID)

此外,您在第一个联接的AND StudentTests.pkStudentTestID IN (SELECT * FROM @tempTests)子句中有on,但@tempTests中的值与这两个表都无关。

尝试将该谓词移动到最后的where子句,即:

SELECT
     ...
WHERE StudentTests.pkStudentTestID IN (SELECT * FROM @tempTests)

这样做意味着SELECT * FROM @tempTests只会执行一次,而不是针对TestInstances和StudentTests的每一行组合执行。