SQL Server 2008 та новіших версій
У SQL Server 2008 і вище, звичайно, це найшвидший спосіб Convert(date, @date)
. Це може бути повернуто до datetime
або, datetime2
якщо це необхідно.
Що насправді найкраще в SQL Server 2005 і старіших версіях?
Я бачив суперечливі твердження про те, що найшвидше скорочує час від дати в SQL Server, і деякі люди навіть говорили, що проводили тестування, але мій досвід був іншим. Тож давайте проведемо ще більш суворе тестування і дозвольмо всім мати сценарій, щоб, якщо я роблю помилки, люди могли мене виправити.
Плаваючі перетворення неточні
По-перше, я б тримався подалі від перетворення datetime
на float
, оскільки він перетворюється неправильно. Можливо, вам вдасться влучно зробити процедуру видалення часу, але я вважаю, що це погана ідея, оскільки вона неявно повідомляє розробникам, що це безпечна операція, а це ні . Поглянь:
declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
Цьому ми не повинні навчати людей у нашому коді чи на наших прикладах в Інтернеті.
Крім того, це навіть не найшвидший спосіб!
Доказ - Тестування продуктивності
Якщо ви хочете виконати деякі тести самостійно, щоб побачити, як насправді складаються різні методи, тоді вам знадобиться цей сценарій налаштування для запуску тестів далі:
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;
Зверніть увагу, що це створює таблицю 427,57 МБ у вашій базі даних, і її запуск займе приблизно 15-30 хвилин. Якщо ваша база даних мала і встановила ріст 10%, це займе більше часу, ніж якщо ви спочатку встановите достатньо великий розмір.
Тепер щодо фактичного сценарію тестування продуктивності. Зверніть увагу, що цілеспрямовано не повертати рядки назад клієнту, оскільки це шалено дорого для 26 мільйонів рядків і приховує різницю в продуктивності між методами.
Результати роботи
set statistics time on;
GO
declare
@dd date,
@d datetime,
@di int,
@df float,
@dv varchar(10);
select @d = CONVERT(date, Tm) from AllDay;
select @d = CAST(Tm - 0.50000004 AS int) from AllDay;
select @d = DATEDIFF(DAY, 0, Tm) from AllDay;
select @d = FLOOR(CAST(Tm as float)) from AllDay;
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay;
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay;
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay;
select @dd = Tm from AllDay;
select @di = CAST(Tm - 0.50000004 AS int) from AllDay;
select @di = DATEDIFF(DAY, 0, Tm) from AllDay;
select @df = FLOOR(CAST(Tm as float)) from AllDay;
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay;
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay;
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay;
GO
set statistics time off;
Деякі аналізи
Деякі нотатки з цього приводу. Перш за все, якщо ви просто виконуєте GROUP BY або порівняння, немає необхідності перетворювати назад на datetime
. Таким чином, ви можете заощадити трохи процесора, уникаючи цього, якщо вам не потрібне остаточне значення для відображення. Ви навіть можете GROUP BY неперетворене значення і помістити перетворення лише в речення 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
round - це час процесора для зворотного туру назад до 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 мкс. Очевидне покращення в 10 разів здається багато, але, відверто кажучи, досить невелике, поки ви не матимете справу з сотнями тисяч рядків (617 000 рядків = економія за 1 секунду).
Навіть з огляду на це невелике абсолютне вдосконалення, на мій погляд, DateAdd
метод виграє, оскільки це найкраще поєднання продуктивності та чіткості. Відповідь, яка вимагає "магічного числа", - 0.50000004
це колись когось вкусить (п’ять нулів чи шість ???), плюс це важче зрозуміти.
додаткові нотатки
Коли я отримую яке - той час я збираюся змінити , 0.50000004
щоб '12:00:00.003'
побачити , як він робить. Він перетворюється на одне datetime
і те ж значення, і мені стає набагато легше запам'ятати.
Для зацікавлених вищезазначені тести проводились на сервері, де @@ Версія повертає наступне:
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) 9 липня 2008 14:43:34 Авторське право (c) 1988-2008 Microsoft Corporation Standard Edition для Windows NT 5.2 (Build 3790: Service Pack 2)