SQL Server 2008 ve üstü
SQL Server 2008 ve sonrasında, elbette en hızlı yol Convert(date, @date)
. Bu, gerekirse a'ya datetime
veya datetime2
gerekirse geri alınabilir .
SQL Server 2005 ve Daha Eski İçinde Gerçekten En İyi Olan Nedir?
SQL Server'da bir tarihten itibaren saati kısaltmanın en hızlı olanı hakkında tutarsız iddialar gördüm ve hatta bazıları test yaptıklarını söyledi, ancak benim deneyimim farklıydı. Şimdi biraz daha sıkı testler yapalım ve herkesin senaryoya sahip olmasına izin verelim, böylece herhangi bir hata yaparsam insanlar beni düzeltebilir.
Kayan Dönüşümler Doğru Değil
İlk olarak, doğru şekilde dönüştürülmediği datetime
için dönüşümden uzak float
dururdum. Zaman kaldırma işini doğru bir şekilde yapmaktan kurtulabilirsiniz, ancak bunu kullanmanın kötü bir fikir olduğunu düşünüyorum çünkü geliştiricilere bunun güvenli bir işlem olduğunu ve olmadığını dolaylı olarak iletiyor . Bir göz at:
declare @d datetime;
set @d = '2010-09-12 00:00:00.003';
select Convert(datetime, Convert(float, @d));
Bu, insanlara kodumuzda veya çevrimiçi örneklerimizde öğretmemiz gereken bir şey değildir.
Ayrıca, en hızlı yol bile değil!
İspat - Performans Testi
Farklı yöntemlerin gerçekte nasıl yığıldığını görmek için kendi kendinize bazı testler yapmak istiyorsanız, testleri daha aşağıda çalıştırmak için bu kurulum betiğine ihtiyacınız olacak:
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;
Lütfen bunun veritabanınızda 427.57 MB'lık bir tablo oluşturacağını ve 15-30 dakika gibi bir süre alacağını unutmayın. Veritabanınız küçükse ve% 10 büyümeye ayarlanmışsa, ilk önce yeterince büyük olmanıza göre daha uzun sürecektir.
Şimdi gerçek performans testi komut dosyası için. Lütfen satırları istemciye geri döndürmemenin amaçlı olduğunu unutmayın, çünkü bu 26 milyon satırda çılgınca pahalıdır ve yöntemler arasındaki performans farklılıklarını gizleyecektir.
Performans Sonuçları
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;
Bazı Rambling Analizi
Bununla ilgili bazı notlar. Her şeyden önce, sadece bir GROUP BY veya bir karşılaştırma yapıyorsanız, geri dönmeye gerek yoktur datetime
. Dolayısıyla, görüntüleme amacıyla nihai değere ihtiyacınız olmadığı sürece, bundan kaçınarak bazı CPU'lardan tasarruf edebilirsiniz. Hatta dönüştürülmemiş değeri GROUP BY bile yapabilir ve dönüşümü yalnızca SELECT yan tümcesine koyabilirsiniz:
select Convert(datetime, DateDiff(dd, 0, Tm))
from (select '2010-09-12 00:00:00.003') X (Tm)
group by DateDiff(dd, 0, Tm)
Ayrıca, sayısal dönüşümlerin geri dönüştürülmesinin nasıl biraz daha fazla zaman aldığını datetime
, ancak varchar
dönüşümün neredeyse iki katına çıktığını görün. Bu, CPU'nun sorgulardaki tarih hesaplamasına ayrılan kısmını ortaya çıkarır. CPU kullanımının tarih hesaplamasını içermeyen kısımları vardır ve bu, yukarıdaki sorgularda 19875 ms'ye yakın bir şey gibi görünmektedir. Daha sonra dönüştürme ek bir miktar alır, bu nedenle iki dönüştürme varsa, bu miktar yaklaşık iki kat kullanılır.
Daha muayene ile karşılaştırıldığında ortaya koymaktadır Convert(, 112)
, Convert(, 101)
(daha uzun kullandığından sorgu bazı ek işlemci gideri bulunmaktadır varchar
?) İkinci dönüşüm geri çünkü date
başlangıçtaki dönüşüm olduğu kadar mal olmaz varchar
ile ancak Convert(, 112)
bu kadar yakınsa aynı 20000 ms CPU temel maliyeti.
İşte yukarıdaki analiz için kullandığım CPU zamanıyla ilgili hesaplamalar:
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 , geri dönüş için CPU zamanıdır datetime
.
single , alternatif veri türüne (zaman bölümünü kaldırmanın yan etkisine sahip olan) tek bir dönüşüm için CPU zamanıdır.
taban çıkarılarak hesaplanmasıdır single
iki çağrıları arasındaki fark: single - (round - single)
. Bu, bu veri türüne ve bu veri türünden dönüşümü varsayan ve datetime
her iki yönde de yaklaşık olarak aynı olan bir tahmin rakamıdır . Görünüşe göre bu varsayım mükemmel değil ama yakın çünkü değerlerin hepsi sadece bir istisna dışında 20000 ms'ye yakın.
Bir başka ilginç şey ise, temel maliyetin neredeyse tek Convert(date)
yönteme eşit olmasıdır (sunucu, datetime
veri türünün ilk dört baytından tam sayı gün bölümünü dahili olarak çıkarabildiğinden, neredeyse 0 maliyet olmalıdır ).
Sonuç
Yani tek yönlü varchar
dönüştürme yönteminin yaklaşık 1.8 μs ve tek yönlü DateDiff
yöntemin yaklaşık 0.18 μs sürmesi gibi görünüyor. Bunu, 25.920.000 satır için toplam 18458 ms'lik testimdeki en muhafazakar "temel CPU" süresine dayandırıyorum, yani 23218 ms / 25920000 = 0.18 μs. Görünen 10x iyileştirme çok gibi görünüyor, ancak yüz binlerce satırla uğraşana kadar (617 bin satır = 1 saniye tasarruf) açıkçası oldukça küçük.
Bu küçük mutlak gelişme göz önüne alındığında bile, bence DateAdd
yöntem kazanır çünkü performans ve netliğin en iyi birleşimidir. "Sihirli sayı" gerektiren cevap bir 0.50000004
gün birini ısıracak (beş sıfır veya altı ???), ayrıca anlaşılması daha zor.
ek Notlar
Ne zaman ben değişime gidiyorum biraz zaman alır 0.50000004
için '12:00:00.003'
ve öyle bakın. Aynı datetime
değere dönüştürülür ve hatırlamayı çok daha kolay buluyorum.
İlgilenenler için, yukarıdaki testler @@ Version'un aşağıdakileri döndürdüğü bir sunucuda yapılmıştır:
Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) Temmuz 9 2008 14:43:34 Telif Hakkı (c) 1988-2008 Windows NT 5.2 üzerinde Microsoft Corporation Standard Edition (Derleme 3790: Service Pack 2)