Как удалить временную часть значения datetime (SQL Server)?
вот что я использую:
SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME)
Я думаю, что там может быть более элегантный способ.
требования:
- он должен быть как можно быстрее (чем меньше формы, тем лучше).
- конечный результат должен быть
datetimeтип, а не строку.
6 ответов:
SQL Server 2008 и выше
в SQL Server 2008 и выше, конечно, самый быстрый способ
Convert(date, @date). Это может быть отброшено назад кdatetimeилиdatetime2при необходимости.что действительно лучше в SQL Server 2005 и старше?
я видел противоречивые утверждения о том, что быстрее всего усекать время от даты в SQL Server, и некоторые люди даже сказали, что они проводили тестирование, но мой опыт был другим. Так что давайте сделайте более строгое тестирование и пусть у всех есть сценарий, чтобы, если я сделаю какие-либо ошибки, люди могли меня исправить.
Float Преобразования Не Являются Точными
во-первых, я бы держался подальше от преобразования
datetimeдоfloat, потому что он не преобразует правильно. Вам может сойти с рук точно выполнять удаление времени, но я думаю, что это плохая идея использовать его, потому что он неявно сообщает разработчикам, что это безопасная работа и это не. Взгляните:declare @d datetime; set @d = '2010-09-12 00:00:00.003'; select Convert(datetime, Convert(float, @d)); -- result: 2010-09-12 00:00:00.000 -- oopsэто не то, что мы должны учить людей в нашем коде или в наших примерах онлайн.
кроме того, это даже не самый быстрый способ!
Доказательство – Тестирование Производительности
если вы хотите выполнить некоторые тесты самостоятельно, чтобы увидеть, как различные методы действительно складываются, то вам понадобится этот сценарий установки для запуска тестов дальше вниз:
create table AllDay (Tm datetime NOT NULL CONSTRAINT PK_AllDay PRIMARY KEY CLUSTERED); declare @d datetime; set @d = DateDiff(Day, 0, GetDate()); insert AllDay select @d; while @@ROWCOUNT != 0 insert AllDay select * from ( select Tm = DateAdd(ms, (select Max(DateDiff(ms, @d, Tm)) from AllDay) + 3, Tm) from AllDay ) X where Tm < DateAdd(Day, 1, @d); exec sp_spaceused AllDay; -- 25,920,000 rowsобратите внимание, что это создает таблицу 427.57 MB В вашей базе данных и займет примерно 15-30 минут для запуска. Если ваша база данных мала и установлена на 10% роста это займет больше времени, чем если Вы размер достаточно большой в первую очередь.
теперь для фактического сценария тестирования производительности. Обратите внимание, что целесообразнее не возвращать строки обратно клиенту, так как это безумно дорого на 26 миллионов строк и скроет различия в производительности между методы.
Результаты
set statistics time on; -- (All queries are the same on io: logical reads 54712) GO declare @dd date, @d datetime, @di int, @df float, @dv varchar(10); -- Round trip back to datetime select @d = CONVERT(date, Tm) from AllDay; -- CPU time = 21234 ms, elapsed time = 22301 ms. select @d = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 23031 ms, elapsed = 24091 ms. select @d = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23782 ms, elapsed = 24818 ms. select @d = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 36891 ms, elapsed = 38414 ms. select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 102984 ms, elapsed = 109897 ms. select @d = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 103390 ms, elapsed = 108236 ms. select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 123375 ms, elapsed = 135179 ms. -- Only to another type but not back select @dd = Tm from AllDay; -- CPU time = 19891 ms, elapsed time = 20937 ms. select @di = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 21453 ms, elapsed = 23079 ms. select @di = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23218 ms, elapsed = 24700 ms select @df = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 29312 ms, elapsed = 31101 ms. select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 64016 ms, elapsed = 67815 ms. select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 64297 ms, elapsed = 67987 ms. select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 65609 ms, elapsed = 68173 ms. GO set statistics time off;Какой-То Бессвязный Анализ
некоторые заметки об этом. Прежде всего, если просто выполнить группу или сравнение, нет необходимости конвертировать обратно в
datetime. Таким образом, вы можете сохранить некоторый процессор, избегая этого, если вам не нужно окончательное значение для целей отображения. Вы даже можете сгруппировать по необращенному значению и поместить преобразование только в SELECT статья:select Convert(datetime, DateDiff(dd, 0, Tm)) from (select '2010-09-12 00:00:00.003') X (Tm) group by DateDiff(dd, 0, Tm)кроме того, смотрите, как числовые преобразования занимают немного больше времени, чтобы преобразовать обратно в
datetime, аvarcharпреобразование почти удваивается? Это показывает часть ЦП, которая посвящена вычислению даты в запросах. Есть части использования ЦП, которые не связаны с вычислением даты, и это, по-видимому, что-то близкое к 19875 МС в приведенных выше запросах. Затем преобразование занимает некоторую дополнительную сумму, поэтому, если есть два преобразования, это сумма израсходована примерно в два раза.больше экзаменов показывает, что по сравнению с
Convert(, 112)наConvert(, 101)запрос имеет некоторые дополнительные расходы на процессор (так как он использует более длинныйvarchar?), потому что второе преобразование обратно вdateне стоит столько, сколько первоначальное преобразование вvarchar, но сConvert(, 112)это ближе к той же 20000 МС базовой стоимости процессора.вот те вычисления на процессорном времени, которые я использовал для выше анализ:
method round single base ----------- ------ ------ ----- date 21324 19891 18458 int 23031 21453 19875 datediff 23782 23218 22654 float 36891 29312 21733 varchar-112 102984 64016 25048 varchar-101 123375 65609 7843
круглые это процессорное время для обратной поездки в
datetime.single это процессорное время для одного преобразования в альтернативный тип данных (тот, который имеет побочный эффект удаления части времени).
базовый это расчет вычитания из
singleразница между двумя вызовами:single - (round - single). Это примерная цифра, которая предполагает преобразование в и из этого типа данных иdatetimeпримерно то же самое в любом направлении. Похоже, это предположение не идеально, но близко, потому что все значения близки к 20000 МС только с одним исключением.еще одна интересная вещь заключается в том, что базовая стоимость почти равна единице
Convert(date)метод (который должен быть почти 0 затрат, так как сервер может внутренне извлечь целую дневную порцию прямо из первые четыре байтаdatetimeтип данных).вывод
так что это похоже на то, что однонаправленный
varcharметод преобразования занимает около 1,8 МКС и однонаправленныйDateDiffметод занимает около 0,18 МКС. Я основываю это на самом консервативном времени "базового процессора" в моем тестировании 18458 МС всего для 25 920 000 строк, поэтому 23218 МС / 25920000 = 0,18 МКС. Очевидное улучшение 10x кажется большим, но это, честно говоря, довольно мало пока вы имеете дело с сотнями тысяч строк (617k строк = 1 секунда экономии).даже учитывая это небольшое абсолютное улучшение, на мой взгляд,
DateAddметод выигрывает, потому что это лучшее сочетание производительности и ясности. Ответ, который требует "магическое число"0.50000004собирается укусить кого-нибудь (пять нулей или шесть???), плюс это сложнее понять.Дополнительная Информация
когда я получаю некоторое время Я собираюсь изменить
0.50000004до'12:00:00.003'и посмотреть, как он делает. Он преобразуется в то же самоеdatetimeзначение и я считаю, что это гораздо легче запомнить.для тех, кто заинтересован, вышеуказанные тесты были запущены на сервере, где @ @ Version возвращает следующее:
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) Jul 9 2008 14: 43: 34 Copyright (c) 1988-2008 Microsoft Corporation Standard Edition на Windows NT 5.2 (сборка 3790: пакет обновления 2)
SQL Server 2008 имеет новый дата тип данных и это упрощает эту проблему:
SELECT CAST(CAST(GETDATE() AS date) AS datetime)
Ицик Бен-Ган в вычисления даты и времени, Часть 1 (журнал SQL Server, февраль 2007 г.) показывает три способа выполнения такого преобразования (от самого медленного до самого быстрого; разница между вторым и третьим методом является маленькая):
SELECT CAST(CONVERT(char(8), GETDATE(), 112) AS datetime) SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) SELECT CAST(CAST(GETDATE() - 0.50000004 AS int) AS datetime)ваша техника (приведение к float) предлагается читателем в апрельском номере журнала. По его словам, он имеет производительность, сопоставимую со второй техникой, представленной выше.
код
CAST-FLOOR-CASTуже кажется оптимальным способом, по крайней мере, на MS SQL Server 2005.некоторые другие решения, которые я видел, имеют преобразование строк, например
Select Convert(varchar(11), getdate(),101)в них, что медленнее в 10 раз.
SQL2005: я рекомендую cast вместо dateadd. Например,
select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)в среднем около 10% быстрее на моем наборе данных, чем
select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)(и кастинг в smalldatetime был еще быстрее)
Comments