Преобразование полей даты и времени SQL-сервера для сравнения только частей даты с индексированными поисками - PullRequest
28 голосов
/ 09 декабря 2008

Я делал convert(varchar,datefield,112) для каждого поля даты, которое я использую в промежуточных запросах на SQL-сервере, чтобы гарантировать, что я только учитываю даты и не пропускаю ни одного, основываясь на временной части datetime поля.

Теперь я слышал, что преобразователи не индексируются и что в SQL Server 2005 есть более эффективные методы для сравнения части даты и времени в запросе, чтобы определить, попадают ли даты в диапазон.

Каков оптимальный, индексируемый способ сделать что-то вроде этого:

select * from appointments
where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'

Ответы [ 5 ]

66 голосов
/ 09 декабря 2008

Лучший способ удалить часть времени поля datetime - это использовать функции datediff и dateadd.

   DateAdd(day, datediff(day,0, MydateValue), 0)

Это использует тот факт, что SQL Server хранит даты в виде двух целых чисел, одно из которых представляет количество дней с дня "0" - (1 января 1900 года), а второе - число * 1005. * тики (каждый тик составляет около 3,33 мс) с полуночи (для времени) *.

формула выше просто должна прочитать только первое целое число. Там нет преобразования или обработки не требуется, поэтому это очень быстро.

Чтобы ваши запросы использовали индекс ... сначала используйте эту формулу для входных параметров фильтрации или на "другой" стороне знака равенства из поля даты и времени таблиц, чтобы оптимизатору запросов не приходилось выполните вычисление для каждого поля даты и времени в таблице, чтобы определить, какие строки удовлетворяют предикату фильтра. Это делает ваш аргумент поиска "SARG-способным" (Search ARGument)

Where MyDateTimeColumn > DateAdd(day, 
      datediff(day,0, @MydateParameter), 0)    -- SARG-able

вместо

Where DateAdd(day, datediff(day,0, 
      MyDateTimeColumn ), 0) > @MydateParameter -- Not SARG-able

* ПРИМЕЧАНИЕ. Внутренне, второе целое число (часть времени) хранит тики. В день 24 х 60 х 60 х 300 = 25 920 000 тиков (по счастливой случайности чуть ниже максимального значения, которое может содержать 32-битное целое число). Однако вам не нужно беспокоиться об этом при арифметическом изменении даты и времени ... При добавлении или вычитании значений из даты и времени вы можете рассматривать значение как дробь, как если бы она была точно равна дробной части дня, как если бы полное значение datetime было числом с плавающей запятой, состоящим из целой части, представляющей дату, и дробной части, представляющей время). т.е.

`Declare @Dt DateTime  Set @Dt = getdate()  
 Set @Dt = @Dt + 1.0/24  -- Adds one hour  
 Select @Dt  
 Set @Dt = @Dt - .25 -- Moves back 6 hours  
 Select @Dt`
5 голосов
/ 09 декабря 2008

Преобразование числовых типов в строковые значения (тип бокса) - не самый эффективный метод выполнения того, что вы ищете. На самом деле это не относится к индексу, потому что фактическим типом столбца является дата и время.

Если вы ищете лучший способ запроса дат, то ваш пример верен, но вы можете учесть разницу в точности 3 мс в MSSQL. Это может означать, что записи за один день могут отображаться в результате за другой день.

Это

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<'08-15-2008'

Должно быть это

select * from appointments where appointmentDate>='08-01-2008' and appointmentDate<='08-14-2008 23:59:59.996'
2 голосов
/ 09 декабря 2008

Это правильно - выполнение преобразования выполнит преобразование для каждой запрошенной строки. Лучше оставить столбцы с датами в качестве дат и передать предложения where в качестве дат:

select * from appointments where appointmentdate between 
'08/01/2008' AND '08/16/2008'

Примечание. Оставить время означает полночь (00: 00.000), так что вы будете включать все время для 08/01, и все время с 08/15, и все, что точно 16.08.2008 00:00: 00

1 голос
/ 09 декабря 2008

Вычислите постоянный столбец, чтобы вычислить нужное вам выражение. Если столбцы вычисляются и сохраняются, они также могут быть проиндексированы.

0 голосов
/ 28 сентября 2011

Существует также способ, описанный в http://www.stillnetstudios.com/comparing-dates-without-times-in-sql-server/

SELECT CAST(FLOOR(CAST( getdate() AS float )) AS datetime)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...