SORU
5 AĞUSTOS 2008, Salı


Nasıl bir datetime değeri (SQL Server) saat kısmını kaldırmak için?

Kullandığım şey şu:

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

Daha şık daha iyi bir yol olabilir diye düşünüyorum.

Gereksinimler:

  • Mümkün olduğunca hızlı (daha az oyuncu daha iyi olmalı
  • Sonuç datetime türü, bir dize değil

CEVAP
12 EYLÜL 2010, Pazar


Gerçekten En İyi Nedir?

En hızlı ne hakkında tutarsız iddiaları SQL Server, bir tarih, zaman kesiliyor gördüm, ve bazı insanlar bile test yaptıklarını söyledi, ama benim deneyim farklı oldu. O yüzden daha sıkı bazı testler yapalım ve herkes komut ver eğer herhangi bir hata yaparsam insanlar beni düzeltin.

Şamandıra Dönüşüm Doğru Değildir

İlk olarak, doğru dönüştürmez çünkü datetime şamandıra dönüştürülmesi dururdum. Uzaklara doğru zaman kaldırılması şeyi yapıyor, ama kötü bir fikir olarak bu güvenli bir işlem olduğunu geliştiriciler için iletişim kurar, çünkü bunu kullanmak için sanırımdeğil. Bir göz atın:

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 örnekler bizim online kodumuzu ya da ders almamız gereken bir şey değil.

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

Kanıt – Performans Testi

Eğer bazı testler kendinizi farklı yöntemler gerçekten yığını nasıl görmek için gerçekleştirmek istiyorsanız, o zaman bu kurulum komut testleri uzağa çalıştırmak için 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;  -- 25,920,000 rows

Lütfen bu veritabanınızda 427.57 MB bir tablo oluşturur ve 15-30 dakika gibi bir şey çalıştırmak için gerekir. Veritabanı küçük ve  büyümeye eğer daha uzun eğer yeterince büyük ilk boyutu fazla sürebilir.

Gerçek performans için şimdi senaryoyu test. Lütfen maksatlı bu 26 milyon satır üzerinde deli gibi pahalı olarak satır istemciye geri dönmek için olduğunu unutmayın ve performans yöntemleri arasındaki farklar saklası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ı Saçma Sapan Analiz

Bu konu hakkında bazı notlar. Eğer sadece bir GRUP ya da bir karşılaştırma gerçekleştirmeden önce, datetime geri dönüştürmeye gerek yok. Görüntüleme amacıyla son değer ihtiyacın yoksa o kaçınarak bazı CPU kaydedebilirsiniz. Hatta din değerine GÖRE GRUP ve SELECT yan tümcesi yalnızca 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 sadece datetime geri dönüştürmek için biraz daha fazla zaman alacak, ama varchar dönüşüm neredeyse iki katına çıkar. Bu sorgularda hesaplama tarihe geçer CPU bölümünü ortaya çıkarır. Tarih hesaplama içermeyen CPU kullanımı parçaları vardır, ve bu bir şey yukarıdaki sorgularda 19875 ms yakın görünüyor. Sonra dönüşüm bazı ek miktar alır, eğer iki hadise varsa bu miktarın yaklaşık iki katı kadar kullanılır.

Daha fazla inceleme Convert(, 112), Convert(, 101) sorgu bazı ek CPU gider (varchar? bir daha) kullandığından, kıyasla ortaya koymaktadır ikinci dönüşüm tarihi için geri Convert(, 112) ile bir INSERT deyim ilk olarak dönüşüm, ama o kadar pahalı da değil çünkü aynı 20000 ms CPU base maliyet daha da yakındır.

Burada analiz için yukarıda kullandığım CPU süresi 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
  • yuvarlakgidiş-dönüş datetime için CPU zamanı.

  • tekCPU alternatif veri türü (saat bölümünü kaldırarak yan etkisi olan) tek bir dönüşüm zamanı.

  • tabanyuvarlak iki çağırmaları arasındaki fark çıkarma hesaplama: tek (tek tur). Ve türü datetime ve her iki yönde de aynıdır yaklaşık verilere dönüştürme varsayan bir rakam. Bu varsayım mükemmel değil gibi görünüyor ama bu değerleri sadece tek bir istisna ile 20000 ms yakındır çünkü bulunur.

Bir daha ilginç bir şey olduğunu temel maliyet neredeyse eşit tek Convert(date) yöntemi (edilmek zorunda neredeyse 0 maliyet, sunucu olabilir içten özü tamsayı gün bölümü hemen ilk dört bayt datetime veri türü).

Sonuç

Yani göründüğü gibi-tek yön varchar dönüştürme yöntemi 1.8 us hakkında alır ve yön tek Ta yöntemi hakkında 0.18 açıklamalardan alır. "CPU" 18458 benim test zaman 25,920,000 satır, 23218 ms = 0.18 / 25920000 açıklamalardan ms toplam. baz en muhafazakar bu kurdum 10x belirgin iyileşme bir sürü gibi görünüyor, ama binlerce satır (=1 617k satır ikinci tasarruf) yüzlerce ile ilgileniyor kadar açıkçası oldukça küçük.

Bence küçük de olsa mutlak bu gelişme göz önüne alındığında, Öncesi yöntem performans en iyi kombinasyonu ve netlik olduğu için kazanır. Gerektiren bir cevap "0.50000004 biri bir gün ısıracak" (sıfır beş veya altı???), sihirli sayı artı daha iyi anlaşılır.

Ek Notlar

'12:00:00.003' ve bunu nasıl yaptığını görmek. 0.50000004 değiştireceğim vakit bulursam Aynı datetime değeri dönüştürülür ve çok daha rahat hatırlıyorum.

İlgilenenler için, yukarıdaki testleri @@Sürümü aşağıdaki verir, bir sunucu üzerinde çalışacak:

Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X 86) 9 Temmuz 2008 14:43:34 Telif hakkı (c) 1988-2008 Microsoft Corporation Standard Edition, Windows NT 5.2 (Build 3790: Service Pack 2)

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Eric Anthony

    Eric Anthony

    13 AĞUSTOS 2011
  • TheDamnWreckless

    TheDamnWreck

    12 Temmuz 2010
  • Top Gear

    Top Gear

    27 Mart 2006