Из-за того, что условие соединения более эксклюзивно, запрос зависает - PullRequest
2 голосов
/ 02 июня 2011

Извините за стену 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 ]

4 голосов
/ 02 июня 2011

Взгляните на свой план выполнения. Я предполагаю, что выполнение вычисления в объединении, также известном как (TestInstancesPre.fkSchoolYearID + 1), приводит к тому, что индексы используются неправильно Простой способ проверить это состоит в том, чтобы изменить ваше присоединение на:

TestInstances.fkSchoolYearID = TestInstancesPre.fkSchoolYearID 

Я видел, как производительность снижается, когда я выполняю прикольные вещи в объединении. Вещи как:

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

Я полагаю, что это потому, что запрос становится невыносимым. Взгляните на этот пост , чтобы узнать об этом подробнее.

0 голосов
/ 02 июня 2011

Имея расчет в вашем сравнении, он может лишить законной силы использование индекса. Обычно это происходит, когда тип данных результата вычисления отличается от типа данных индексируемого столбца. Иногда стоимость расчета велика, если она должна повторяться достаточно много раз (например, из множества соединений). Одним из решений является сохранение рассчитанного значения в специальном столбце, например:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...