Лучший способ проверить текущую дату в предложении where sql-запроса

Я пытаюсь найти наиболее эффективный (лучший по производительности) способ проверить поле даты на текущую дату. В настоящее время мы используем:

SELECT     COUNT(Job) AS Jobs
FROM         dbo.Job
WHERE     (Received BETWEEN DATEADD(d, DATEDIFF(d, 0, GETDATE()), 0)
                        AND DATEADD(d, DATEDIFF(d, 0, GETDATE()), 1))

Обратите внимание, что выбранный вами ответ НЕ является лучшим способом производительности. Ваш путь близок к правильному, вам просто нужно переключиться на> = и <, а не использовать BETWEEN (что похоже на <= во втором условии и неверно).

ErikE 13.09.2010 04:12
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
6
1
28 878
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

это лучший способ сделать это. вы можете поместить DATEADD (d, DATEDIFF (d, 0, GETDATE ()), 0) и DATEADD (d, DATEDIFF (d, 0, GETDATE ()), 1) в переменные и использовать их вместо этого, но я не думаю, что это улучшит производительность.

Если вы просто хотите найти все записи с сегодняшней датой получения и есть записи с будущими датами получения, то то, что вы делаете (очень-очень незначительно), неверно ... Поскольку оператор Between допускает равные значения до конечной границы, чтобы вы могли получать записи с датой получения = до полуночи завтра ...

Если нет необходимости использовать индекс для Received, все, что вам нужно сделать, это проверить, что разница даты с текущим datetime равна 0 ...

Where DateDiff(day, received, getdate()) = 0

Этот предикат, конечно, не SARGable, поэтому он не может использовать индекс ... Если это проблема для этого запроса, то, если у вас не может быть дат получения в будущем, я бы использовал это вместо этого ...

Where Received >= DateAdd(day, DateDiff(Day, 0, getDate()), 0) 

Если даты получения могут быть в будущем, то вы, вероятно, настолько близки к наиболее эффективным, насколько это возможно ... (за исключением изменения значения Between на> = AND <)

Чарльз, даже без индекса DateDiff(day, received, getdate()) не лучший вариант, потому что он заставляет вычислять каждую строку в таблице, без всякой причины используя больше ЦП.

ErikE 13.09.2010 04:15

@Emtucifor, верно, но по сравнению с чтением дискового ввода-вывода, циклы процессора настолько незначительны, что не имеют значения. Здесь мы говорим о разнице на три-четыре порядка.

Charles Bretana 13.09.2010 06:42

Верно, Чарльз. Спасибо, что взглянули на мои придирки в перспективе. :) Я действительно думаю, что лучше рекомендовать последнее, где это возможно, потому что, когда есть индекс, это серьезно повлияет на ввод-вывод.

ErikE 13.09.2010 08:08

@Emtucifor, вы снова правы ... и, конечно, лучше всего, когда у вас есть на это право, - это установить соответствующий индекс и разработать запросы для их использования.

Charles Bretana 13.09.2010 16:08
Ответ принят как подходящий
WHERE
  DateDiff(d, Received, GETDATE()) = 0

Обновлено: как указано в комментариях к этому ответу, это не идеальное решение. Проверьте и другие ответы в этой теме.

Я бы не стал так поступать, потому что это не поддерживает SARG.

Mitch Wheat 28.11.2008 18:04

@Mitch Wheat: Пока нет столбца только с датой И указателем на нем, ничего из того, что вы можете сделать, все равно будет SARGable.

Tomalak 28.11.2008 18:13

Tomalak, нет - его первоначальное решение SARGable ... Где было получено> = {Midnight This morning} And Received <{Midnight Tonight} - SARGable

Charles Bretana 28.11.2008 18:45

Хорошие моменты о SARGable. Какое тогда решение было бы оптимальным?

kristof 28.11.2008 18:49

если вы собираетесь сделать это таким образом, то нет смысла отдельно вычислять DateDiff ((d, 0, getdate ()) ... Просто выполните single dateiff - вычислите DateDiff beterrn Received и getdate () - должно быть равно нулю для все даты за сегодня Где DateDiff (d, Received, getDate ()) = 0

Charles Bretana 28.11.2008 20:45

База данных может не использовать индекс. (как MSSQL 2000/2005)

Dennis C 01.12.2008 08:46

Что, черт возьми, «поддерживает SARG»?

James Curran 01.12.2008 15:27

Это означает, что условие поиска может быть выполнено с помощью индекса (en.wikipedia.org/wiki/Sargable). Вычисление значения, по которому выполняется фильтрация, делает операцию недоступной для SARG, поскольку вычисленные значения не входят в индекс. Это заставляет сервер смотреть на каждую строку отдельно (= медленно).

Tomalak 01.12.2008 16:48

ага ... Я подумал, что это было что-то вроде этого (я бы википедию написал "SARG", но ничего не нашел)

James Curran 01.12.2008 20:25

Этот метод не годится. Даже если в столбце ReceivedDate нет индекса, зачем заставлять ядро ​​базы данных выполнять преобразование для каждой отдельной строки, а не только один раз? Выполните расчет и используйте синтаксис диапазона дат.

ErikE 13.09.2010 04:11

Он спрашивает, как лучше всего, а этот не использует индексы. НЕ ИСПОЛЬЗУЙТЕ ЕГО. Период..

sotn 26.04.2017 11:55

... как я сказал в своем ответе, который вы на самом деле не читали, хотя он находится в предложении непосредственно под кодом.

Tomalak 26.04.2017 13:09

Я не уверен, как вы определяете «лучший», но это сработает.

Однако, если вы собираетесь запускать этот запрос неоднократно, вам следует избавиться от функции get_date () и просто вставить туда буквальное значение даты с помощью любого языка программирования, на котором вы его запускаете. Несмотря на то, что их вывод изменяется только один раз каждые 24 часа get_date (), current_date () и т. д. являются функциями недетерминированный, что означает, что ваша RDMS, вероятно, сделает запрос недействительным как кандидата для сохранения в своем кэше запросов, если он у него есть.

Как насчет

 WHERE
      DATEDIFF(d, Received, GETDATE()) = 0

Это не лучший способ. См. Сообщение Марка Грейвелла, чтобы узнать лучше.

ErikE 13.09.2010 04:13

Обычно я бы использовал решение, предложенное Томалаком, но если вы действительно отчаянно нуждаетесь в производительности, лучшим вариантом может быть добавление дополнительного индексированного поля ReceivedDataPartOnly, которое будет хранить данные без временной части, а затем использовать запрос

declare @today as datetime
set @today = datediff(d, 0, getdate())

select     
    count(job) as jobs
from         
    dbo.job
where     
    received_DatePartOnly = @today

Решение, предложенное Томалаком, далеко не лучшее.

ErikE 13.09.2010 04:13

Если вам нужна производительность, вам нужно, чтобы индекс непосредственный попадал в индекс без использования ЦП и т. д. На строку; поэтому я бы вычислил диапазон первый, а затем использовал бы простой запрос WHERE. Я не знаю, какой db вы используете, но в SQL Server работает следующее:

// ... where @When is the date-and-time we have (perhaps from GETDATE())
DECLARE @DayStart datetime, @DayEnd datetime
SET @DayStart = CAST(FLOOR(CAST(@When as float)) as datetime) -- get day only
SET @DayEnd = DATEADD(d, 1, @DayStart)

SELECT     COUNT(Job) AS Jobs
FROM         dbo.Job
WHERE     (Received >= @DayStart AND Received < @DayEnd)

Я не совсем понимаю, что вы подразумеваете под "прямым" попаданием в индекс? если вы просто говорите о том, что есть вычисление на «другой» стороне оператора предиката, вместо того, чтобы предварительно вычислить его перед выполнением индекса, то либо A) вычисленное значение основано на каком-либо другом столбце в таблице и не то же самое для сгенерированной строки, поэтому она должна быть в sql, или B) если это одно и то же значение для каждой сгенерированной строки, обработчик запросов все равно предварительно вычислит ее, поэтому она БУДЕТ вычисляться только один раз, нет независимо от того, сколько строк выдает запрос.

Charles Bretana 13.09.2010 16:12

Сравните две даты после преобразования в тот же формат, как показано ниже.

where CONVERT(varchar, createddate, 1) = CONVERT(varchar, getdate(), 1);

Другие вопросы по теме