Лучший подход для удаления временной части datetime в SQL Server

Какой метод обеспечивает лучшую производительность при удалении временной части из поля datetime в SQL Server?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

или

b) select cast(convert(char(11), getdate(), 113) as datetime)

Второй способ отправляет еще несколько байтов в любом случае, но это может быть не так важно, как скорость преобразования.

Оба тоже кажутся очень быстрыми, но может быть разница в скорости при работе с сотнями тысяч или более строк?

Кроме того, возможно ли, что есть еще лучшие методы, чтобы избавиться от временной части datetime в SQL?

Ответ 1

Строго говоря, метод является наименее ресурсоемким: a

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Доказано, что процессор требует меньше ресурсов при той же общей продолжительности - миллион строк, причем слишком много времени у них на руках: самый эффективный способ в SQL Server получить дату от даты + время?

Я видел аналогичный тест в другом месте с аналогичными результатами тоже.

Я предпочитаю DATEADD/DATEDIFF, потому что:

  • varchar подвержен проблемам с языком/датой форматирования
    Пример: почему мое выражение CASE недетерминировано?
  • float полагается на внутреннюю память
  • он распространяется на первый день месяца, завтра и т.д., изменяя базу на 0

Редактировать, октябрь 2011

Для SQL Server 2008+ вы можете CAST на date. Или просто используйте date поэтому нет времени, чтобы удалить.

Редактировать, январь 2012

Работающий пример того, насколько это гибко: нужно рассчитать по округленному времени или дате на сервере SQL

Редактировать, май 2012

Не используйте это в предложениях WHERE и т.п., Не задумываясь: добавление функции или CAST к столбцу делает недействительным использование индекса. Смотрите номер 2 здесь: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/

Теперь есть пример более поздних версий оптимизатора SQL Server, которые корректно управляют CAST, но в целом это будет плохая идея...

Изменить, сентябрь 2018 года, для datetime2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2epoch datetime2 = '19000101'

select DATEADD(dd, DATEDIFF(dd, @datetime2epoch, @datetime2value), @datetime2epoch)

Ответ 2

В SQL Server 2008 вы можете использовать:

CONVERT(DATE, getdate(), 101)

Ответ 3

Конечно, это старый поток, но для его завершения.

Из SQL 2008 вы можете использовать тип данных DATE, чтобы вы могли просто:

SELECT CONVERT(DATE,GETDATE())

Ответ 4

SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)

... не очень хорошее решение, согласно комментариям ниже.

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

Ответ 5

В SQL Server 2008 существует тип данных DATE (также тип данных TIME).

CAST(GetDate() as DATE)

или

declare @Dt as DATE = GetDate()

Ответ 6

Вот еще один ответ, из другого дублирующего вопроса:

SELECT CAST(CAST(getutcdate() - 0.50000004 AS int) AS datetime) 

Этот метод магического числа выполняется немного быстрее, чем метод DATEADD. (Это похоже на ~ 10%)

Время процессора в нескольких раундах миллиона записей:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

Но обратите внимание, что эти цифры, возможно, не имеют значения, потому что они уже очень быстрые. Если бы у меня не было записей на 100 000 и более, я бы даже не мог заставить процессорное время читать выше нуля.

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

Ответ 7

SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)

Ответ 8

Мне очень нравится:

[date] = CONVERT(VARCHAR(10), GETDATE(), 120)

Формат формата 120 будет поддерживать дату в стандарте ISO 8601:

'YYYY-MM-DD' or '2017-01-09'

Супер прост в использовании в dplyr (R) и pandas (Python)!

Ответ 9

Время разрыва на вставках/обновлениях. Что касается преобразования "на лету", ничто не может превзойти пользовательскую функцию maintanability:

select date_only(dd)

Реализация date_only может быть любой, что вам нравится - теперь она абстрагируется, а код вызова намного чище.

Ответ 11

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

 CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

второй раз я нашел это решение... Я снял этот код

Ответ 12

CAST(round(cast(getdate()as real),0,1) AS datetime)

Этот метод не использует функцию строки. Date - это, по существу, реальный тип данных с цифрами до десятичной дроби - это доля дня.

это, я думаю, будет быстрее, чем много.

Ответ 13

Для меня код всегда побеждает:

SELECT CONVERT(DATETIME, FLOOR(CONVERT(FLOAT,GETDATE())));

Ответ 14

BEWARE!

Метод a) и b) НЕ всегда имеет тот же выход!

select DATEADD(dd, DATEDIFF(dd, 0, '2013-12-31 23:59:59.999'), 0)

Выход: 2014-01-01 00:00:00.000

select cast(convert(char(11), '2013-12-31 23:59:59.999', 113) as datetime)

Выход: 2013-12-31 00:00:00.000

(Протестировано на MS SQL Server 2005 и 2008 R2)

EDIT: согласно комментарию Адама, это не может произойти, если вы читаете значение даты из таблицы, но это может произойти, если вы укажете свое значение даты как литерал (пример: как параметр хранимой процедуры, вызываемой через ADO. NET).

Ответ 15

выберите CONVERT (char (10), GetDate(), 126)

Ответ 16

Я думаю, вы имеете в виду  cast(floor(cast(getdate()as float))as datetime)

real - всего 32 бита и может потерять некоторую информацию

Это самый быстрый cast(cast(getdate()+x-0.5 as int)as datetime)

... хотя только на 10% быстрее (about 0.49 microseconds CPU vs. 0.58)

Это было рекомендовано и в то же время занимает одно и то же время в моем тесте: DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

В SQL 2008 функция SQL CLR примерно в 5 раз быстрее, чем использование функции SQL, было бы в 1,35 микросекундах против 6,5 микросекунд, что указывает на гораздо более низкую накладную функциональность для функции SQL CLR по сравнению с простым SQL UDF.

В SQL 2005 функция CLR SQL в 16 раз быстрее, по моему тестированию, против этой медленной функции:

create function dateonly (  @dt datetime )
returns datetime
as
begin
return cast(floor(cast(@dt as float))as int)
end

Ответ 17

Я думаю, что если вы строго придерживаетесь TSQL, это самый быстрый способ усечения времени:

 select convert(datetime,convert(int,convert(float,[Modified])))

Я нашел этот метод усечения примерно на 5% быстрее, чем метод DateAdd. И это можно легко изменить до округления до ближайшего дня следующим образом:

select convert(datetime,ROUND(convert(float,[Modified]),0))

Ответ 18

Как насчет select cast(cast my_datetime_field as date) as datetime)? Это приводит к той же дате с временем, установленным в 00:00, но избегает любого преобразования в текст, а также избегает любого явного округления чисел.

Ответ 19

На всякий случай, если кто-то ищет здесь версию Sybase, так как некоторые из вышеперечисленных версий не работают

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • Протестировано в я SQL v11, запущенном на Adaptive Server 15.7

Ответ 20

Здесь я сделал функцию для удаления некоторых частей datetime для SQL Server. Использование:

  • Первый параметр - это время, которое нужно удалить.
  • Второй параметр - char:
    • s: от раундов до секунд; удаляет миллисекунды
    • m: раунды до минут; удаляет секунды и миллисекунды.
    • ч: от раундов до часов; удаляет минуты, секунды и миллисекунды.
    • d: раунды до дней; удаляет часы, минуты, секунды и миллисекунды.
  • Возвращает новое datetime

create function dbo.uf_RoundDateTime(@dt as datetime, @part as char) returns datetime as begin if CHARINDEX( @part, 'smhd',0) = 0 return @dt; return cast( Case @part when 's' then convert(varchar(19), @dt, 126) when 'm' then convert(varchar(17), @dt, 126) + '00' when 'h' then convert(varchar(14), @dt, 126) + '00:00' when 'd' then convert(varchar(14), @dt, 112) end as datetime ) end

Ответ 21

Я лично почти всегда использую Пользовательские функции для этого, если вы имеете дело с SQL Server 2005 (или более низкой версией), однако, это следует отметить, что существуют определенные недостатки в использовании UDF, особенно если они применяются к предложениям WHERE (см. ниже и комментарии к этому ответу для получения дополнительной информации). Если используется SQL Server 2008 (или выше) - см. Ниже.

Фактически, для большинства создаваемых баз данных я добавляю эти UDF прямо в начале, так как я знаю, что 99% вероятность, что я буду нуждаться в них рано или поздно.

Я создаю один для "только дата" и "только время" (хотя "дата только" одна из них наиболее часто используется для двух).

Здесь некоторые ссылки на различные связанные с датой UDF:

Основные функции даты, времени и даты SQL Server
Функция только для получения даты

Эта последняя ссылка показывает не менее 3 различных способов получения даты только частью поля datetime и упоминает некоторые плюсы и минусы каждого подхода.

При использовании UDF следует отметить, что вам следует попытаться избежать использования UDF как части предложения WHERE в запросе, поскольку это значительно затруднит выполнение запроса. Основная причина этого заключается в том, что использование UDF в предложении WHERE делает это предложение как non-sargable, что означает, что SQL Server больше не может используйте индекс с этим предложением, чтобы повысить скорость выполнения запроса. Что касается моего собственного использования UDF, я часто использую столбец "raw" date в предложении WHERE, но применяю UDF к столбцу SELECTed. Таким образом, UDF применяется только к фильтруемому набору результатов, а не к каждой строке таблицы как части фильтра.

Конечно, самым лучшим подходом для этого является использование SQL Server 2008 (или выше) и выделение дат и времени, поскольку механизм базы данных SQL Server затем обеспечивает индивидуальные компоненты даты и времени и может эффективно запрашивать их независимо, без необходимости использования UDF или другого механизма для извлечения либо даты, либо временной части из составного типа datetime.

Ответ 22

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

В этом случае:

[Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime DateOnly(SqlDateTime input)
    {
        if (!input.IsNull)
        {
            SqlDateTime dt = new SqlDateTime(input.Value.Year, input.Value.Month, input.Value.Day, 0, 0, 0);

            return dt;
        }
        else
            return SqlDateTime.Null;
    }

Ответ 23

Я бы использовал:

CAST
(
CAST(YEAR(DATEFIELD) as varchar(4)) + '/' CAST(MM(DATEFIELD) as varchar(2)) + '/' CAST(DD(DATEFIELD) as varchar(2)) as datetime
) 

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