SQL MIN в подзапросе вызывает огромную задержку - PullRequest
1 голос
/ 20 апреля 2010

У меня есть SQL-запрос, который я пытаюсь отладить.Он отлично работает для небольших наборов данных, но в больших наборах данных эта конкретная часть заставляет его занимать 45-50 секунд вместо того, чтобы быть менее секунды по скорости.Этот подзапрос является одним из выбранных элементов в большем запросе.Я в основном пытаюсь выяснить, когда самая ранняя дата работы соответствует той же категории, что и текущая строка, на которую мы смотрим (из таблицы dr)

ISNULL(CONVERT(varchar(25),(SELECT MIN(drsd.DateWorked) FROM [TableName] drsd
  WHERE drsd.UserID = dr.UserID
        AND drsd.Val1 = dr.Val1
        OR (((drsd.Val2 = dr.Val2 AND LEN(dr.Val2) > 0) AND (drsd.Val3 = dr.Val3 AND LEN(dr.Val3) > 0) AND (drsd.Val4 = dr.Val4 AND LEN(dr.Val4) > 0))
        OR (drsd.Val5 = dr.Val5 AND LEN(dr.Val5) > 0)
        OR ((drsd.Val6 = dr.Val6 AND LEN(dr.Val6) > 0) AND (drsd.Val7 = dr.Val7 AND LEN(dr.Val2) > 0))))), '') AS WorkStartDate,

Это завершает выполнение поиска ключа18 миллионов раз на столе, который имеет 346 000 записей.Я пытался создать индекс для него, но безуспешно.Кроме того, выбор максимального значения в этом же запросе занимает менее секунды, поскольку он вообще не должен выполняться очень много раз.

Любые предложения другого подхода попробовать?Спасибо!

1 Ответ

4 голосов
/ 20 апреля 2010

Создать составной индекс для drsd (UserID, DateWorked).

Возможно также, что распределение записей в drsd перекошено в сторону больших дат, например:

DateWorked   Condition

01.01.2001   FALSE
02.01.2001   FALSE
…
18.04.2010   FALSE
19.04.2010   TRUE

В этом случае запрос MAX должен просматривать только запись 1, тогда как запрос MIN должен просматривать все записи с 2001 и далее.

В этом случае вам нужно создать четыре отдельных индекса:

UserId, Val1, DateWorked
UserId, Val2, Val3, Val4, DateWorked
UserId, Val5, DateWorked
UserId, Val6, Val7, DateWorked

и переписать подзапрос:

SELECT  MIN(dateWorked)
FROM    (
        SELECT  MIN(DateWorked) AS DateWorked
        FROM    drsd
        WHERE   UserID = dr.UserID
                AND Val1 = dr.Val1
        UNION ALL
        SELECT  MIN(DateWorked)
        FROM    drsd
        WHERE   UserID = dr.UserID
                AND drsd.Val2 = dr.Val2 AND LEN(dr.Val2) > 0
                AND drsd.Val3 = dr.Val3 AND LEN(dr.Val3) > 0
                AND drsd.Val4 = dr.Val4 AND LEN(dr.Val4) > 0
        UNION ALL
        SELECT  MIN(DateWorked)
        FROM    drsd
        WHERE   UserID = dr.UserID
                AND drsd.Val5 = dr.Val5 AND LEN(dr.Val5) > 0
        UNION ALL
        SELECT  MIN(DateWorked)
        FROM    drsd
        WHERE   UserID = dr.UserID
                AND drsd.Val6 = dr.Val6 AND LEN(dr.Val6) > 0
                AND drsd.Val7 = dr.Val7 AND LEN(dr.Val7) > 0
        ) q

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

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