Nasıl bir datetime değeri (SQL Server) saat bölümünü kaldırmak için?

oy
77

İşte ne kullanın:

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

Ben daha iyi ve daha zarif bir şekilde olabilir düşünüyorum.

Gereksinimler:

  • O (iyi, daha az döküm) mümkün olduğunca hızlı olmak zorunda.
  • Nihai sonuç, bir olmak zorunda datetimetipi değil, bir dize.
Oluştur 05/08/2008 saat 21:08
kaynak kullanıcı
Diğer dillerde...                            


6 cevaplar

oy
106

SQL Server 2008 ve yukarı

SQL Server 2008 ve yukarı olarak, tabii ki en hızlı yoludur Convert(date, @date). Bu geri dökülebilir datetimeveya datetime2gerekirse.

Ne SQL Server 2005 ile Yaşlı yılında Gerçekten iyi mi?

Ben SQL Server bir tarihten zaman kesilmesi için en hızlı ne hakkında tutarsız iddialar gördüm ve bazı insanlar bile test yaptım dedi ama benim deneyim farklı olmuştur. O yüzden biraz daha sıkı testleri yapalım ve benden hata İnsanlar bana düzeltebilirsiniz böylece herkes senaryoyu atalım.

Float Dönüşümler Doğru Değildir

Birincisi, dönüştürme uzak kalmak datetimeiçin floatdoğru dönüştürmez, çünkü. Sen doğru zaman-çıkarma şeyi yapıyor paçayı olabilir, ama buna dolaylı olarak bu güvenli bir işlemdir ve bu geliştiricilere iletişim kurar, çünkü kullanmak için kötü bir fikir olduğunu düşünüyorum değil mi . Bir göz at:

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

Bu online bizim kodunda veya örneklerde öğretim insanların olması gereken bir şey değildir.

Ayrıca, hatta en hızlı yolu değil!

Kanıtı - Performans Testleri

Kendinizi farklı yöntemler gerçekten biriktirecek nasıl görmek için bazı testler yapmak istiyorsanız, o zaman daha uzağa aşağı testleri çalıştırmak için bu kurulum komut dosyası gerekir:

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

Bu veritabanındaki bir 427,57 MB tablo oluşturur ve çalıştırmak için 15-30 dakika gibi bir şey alacağını unutmayınız. veritabanı küçük ve% 10 büyüme ayarlı ise o ilk yeterince büyük boyutu ise daha uzun sürer.

Şimdi gerçek performans testi komut dosyası için. Bu 26 milyon satırlarda pahalı deli ve yöntemler arasındaki performans farklılıklarını gizlemek gibi müşteriye geri satırları döndürmez için bu amaca olduğunu unutmayın.

Performans Sonuçları

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;

Bazı Rambling Analizi

Bu konuda bazı notlar. Sadece bir GROUP BY veya karşılaştırma yapmaktan, her şeyden önce, geri dönüştürmek için gerek yoktur datetime. Eğer görüntüleme amacıyla nihai değeri gerekmedikçe Yani, o kaçınarak bazı CPU kaydedebilirsiniz. Sen dönüştürülmemiş değeri TARAFINDAN bile GRUBU ve sadece SELECT yan tümcesinde dönüşüm 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üşüm, yalnızca geri dönüştürmek için biraz daha zaman alabilir nasıl datetimeama varchardönüşüm neredeyse iki katına? Bu sorgularda tarih hesaplaması için ayrılmıştır CPU kısmını ortaya koymaktadır. Orada tarih hesaplama içermeyen CPU kullanımı parçalarıdır ve bu yukarıdaki sorgularda 19875 ms yakın bir şey gibi görünüyor. Iki dönüşüm varsa Ardından dönüşüm, bazı ek miktar alır miktar yaklaşık iki kat yukarı 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 varcharsırt ikinci dönüşüm, çünkü?) dateIçin ilk dönüşüm olarak çok mal olmaz varchar, fakat Convert(, 112)buna 20000 aynı yakındır MS CPU temel maliyeti.

İşte yukarıdaki analizi için kullanılan işlemci zamanında bu hesaplamalar şunlardır:

     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
  • yuvarlak geri gidiş-dönüş için CPU zamanı datetime.

  • Tek bir alternatif veri türü (zaman kısmını seçici olarak çıkarma yan etkisi vardır bir) tek bir dönüştürme için işlemci zamandır.

  • taban çıkarılarak hesaplanmasıdır singleiki çağrıları arasındaki fark: single - (round - single). Bu ve bu veri tipinden dönüĢtüğünü ve bir rakam bu datetimeyaklaşık iki yönde aynıdır. Varsayım mükemmel değildir görünür ancak değerler sadece bir istisna dışında 20000 ms tüm yakın olduğu için yakındır.

Bir daha ilginç olan taban maliyeti, tek hemen hemen eşit olmasıdır Convert(date)(sunucu dahili doğru ilk dört bayt üzerinden tam sayı gün kısmını çıkarmak için, hemen hemen 0 maliyetli olması gerekmektedir yöntemi datetimeveri türü).

Sonuç

Ne olmuş gibi görünüyor tek yönde olmasıdır varchardönüşüm yöntemi yaklaşık 1.8 us alır ve tek yön DateDiffyöntemi yaklaşık 0.18 us sürer. Öyle 23218 ms / 25920000 = 0.18 mikro saniye, 25920000 satırlar için 18.458 ms toplam benim test en muhafazakar "temel CPU" zamanında bu kurdum. Belirgin 10x iyileşme çok gibi görünüyor, ancak satırların yüzbinlerce ile (617K satır = 1 saniye tasarruf) ilgileniyor kadar açıkçası oldukça küçüktür.

Hatta bu küçük mutlak iyileşme göz önüne alındığında, bence, DateAddbu performans ve netlik en iyi kombinasyonu olduğu için yöntem kazanır. Bir "sihirli sayı" gerektiren cevap ait 0.50000004birisi (beş sıfır ya da altı ???) bir gün ısırmaya gidiyor, artı anlamak zordur.

ek Notlar

Biraz zaman alır zaman değiştirmek için gidiyorum 0.50000004için '12:00:00.003've öyle bakın. Aynı dönüştürülür datetimedeğeri ve ben çok daha kolay hatırlamak için bulabilirsiniz.

ilgilenenler, yukarıda testler @@ Versiyon aşağıdaki döndüren bir sunucuda üzerinde yürütülmüştür:

Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) 9 Temmuz 2008 14:43:34 Telif Hakkı (c) 1988-2008 Microsoft Corporation Standard Edition, Windows NT 5.2 üzerinde (Derleme 3790: Service Pack 2)

Cevap 12/09/2010 saat 23:57
kaynak kullanıcı

oy
27

SQL Server 2008 yeni sahiptir tarih veri türünü ve buna bu sorunu kolaylaştırır:

SELECT CAST(CAST(GETDATE() AS date) AS datetime)
Cevap 06/08/2008 saat 07:44
kaynak kullanıcı

oy
16

Içinde Itzik Ben-Gan DATETIME hesaplamaları, Bölüm 1 (SQL Server Dergisi, Şubat 2007) böyle bir dönüştürme işleminden üç yöntem gösterilmektedir ( yavaş hızlı için , ikinci ve üçüncü yöntemi arasındaki fark küçük):

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)

(Döküm Kişisel tekniği yüzer ) dergisinin Nisan sayısında bir okuyucu tarafından önerilir. Ona göre, yukarıda sunulan ikinci tekniğe karşılaştırılabilir performansa sahiptir.

Cevap 06/08/2008 saat 09:06
kaynak kullanıcı

oy
11

Sizin CAST- FLOOR- CASTzaten en azından MS SQL Server 2005, optimum yol olarak görünmektedir.

Gördüğüm diğer bazı çözümler gibi bir dize-dönüşüm, sahip Select Convert(varchar(11), getdate(),101)10 kat daha yavaş onlarda.

Cevap 05/08/2008 saat 21:12
kaynak kullanıcı

oy
3

Deneyin lütfen:

SELECT CONVERT(VARCHAR(10),[YOUR COLUMN NAME],105) [YOURTABLENAME]
Cevap 29/06/2013 saat 10:49
kaynak kullanıcı

oy
0

SQL2005: Ben yerine dateadd ait döküm önerilir. Örneğin,

select cast(DATEDIFF(DAY, 0, datetimefield) as datetime)

yaklaşık 10 ortalama% daha hızlı daha benim veri kümesi üzerinde

select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0)

(Ve küçük tarih saat içine döküm hala hızlıydı)

Cevap 05/11/2014 saat 04:26
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more