Примечание: Когда я первоначально написал этот ответ, я сказал, что индекс по одному из столбцов может создать запрос, который работает лучше, чем другие ответы (и упомянул ответ Дэна Фуллера). Однако я не думал на 100% правильно. Дело в том, что без вычисляемого столбца или индексированного (материализованного) представления полное сканирование таблицы будет обязательным , потому что сравниваются два столбца даты из той же таблицы !
Я полагаю, что в приведенной ниже информации все еще есть ценность, а именно: 1) возможность повышения производительности в правильной ситуации, например, при сравнении столбцов из разных таблиц, и 2) продвижение привычки разработчиков SQL следовать лучшим практикуйте и изменяйте их мышление в правильном направлении.
Условия изготовления Sargable
Лучшая практика, о которой я говорю, это перемещение одного столбца в одиночку с одной стороны от оператора сравнения, например:
SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM dbo.MyTable T
WHERE T.EndTime <= T.BegTime + '00:00:10'
Как я уже сказал, это не избежит сканирования одной таблицы, однако в такой ситуации это может иметь огромное значение:
SELECT InitialSave = DateDiff(second, T.BegTime, T.EndTime)
FROM
dbo.BeginTime B
INNER JOIN dbo.EndTime E
ON B.BeginTime <= E.EndTime
AND B.BeginTime + '00:00:10' > E.EndTime
EndTime
в обоих условиях теперь один на одной стороне сравнения. Предполагая, что таблица BeginTime
имеет намного меньше строк, а таблица EndTime
имеет индекс для столбца EndTime
, это будет работать намного лучше, чем что-либо, использующее DateDiff(second, B.BeginTime, E.EndTime)
. Теперь это sargable , что означает, что существует действительный «аргумент поиска» - так как механизм сканирует таблицу BeginTime
, он может искать в EndTime
таблица. Требуется тщательный выбор того, какой столбец находится на одной стороне от оператора - может быть стоит поэкспериментировать, поставив BeginTime
отдельно, выполнив некоторую алгебру для переключения на AND B.BeginTime > E.EndTime - '00:00:10'
Точность DateDiff
Я должен также указать, что DateDiff
не возвращает истекшего времени, а вместо этого подсчитывает количество пересеченных границ . Если вызов DateDiff
с использованием секунд вернет 1
, это может означать 3 ms
истекшее время или 1997 ms
! По сути, это точность + - 1 единиц времени. Для большей точности + - 1/2 единицы времени вам понадобится следующий запрос, сравнивающий 0
с EndTime - BegTime
:
SELECT DateDiff(second, 0, EndTime - BegTime) AS InitialSave
FROM MyTable
WHERE EndTime <= BegTime + '00:00:10'
Теперь максимальная ошибка округления составляет всего одну секунду, а не две (по сути, операция floor ()). Обратите внимание, что вы можете только вычесть тип данных datetime
- чтобы вычесть значение date
или time
, которое вам придется преобразовать в datetime
или использовать другие методы, чтобы получить более высокую точность (в целом *) 1060 *, DateDiff
и, возможно, другой мусор, или, возможно, с использованием более высокой точности и деления).
Этот принцип особенно важен при подсчете больших единиц, таких как часы, дни или месяцы. DateDiff
из 1 month
может быть на расстоянии 62 дня (подумайте 1 июля 2013 г. - 31 августа 2013 г.)!