it-swarm-tr.com

SQL Server'da DateTime vs DateTime2

Hangisi: 

the tarih ve saati SQL Server 2008+ 'de saklamak için önerilen yol nedir?

Hassasiyetteki (ve muhtemelen depolama alanındaki) farklılıkların farkındayım, ancak şimdilik bunları göz ardı ederek ne zaman kullanacağımıza dair en iyi uygulama belgesi var mı, yoksa sadece sadece datetime2 kullanmalı mıyız?

667
Mikeon

datetime için MSDN belgeleri datetime2 kullanılmasını önerir. İşte onların tavsiyesi:

time, date, datetime2 ve .__ öğelerini kullanın. new .__ için datetimeoffset veri türleri. iş. Bu türler SQL .__ ile uyumludur. Standart. Onlar daha taşınabilir . time, datetime2 ve datetimeoffset saniye daha fazla hassasiyet sağlar . datetimeoffset, saat dilimi sağlar. küresel konuşlandırılmış için destek. uygulamalar.

datetime2, daha geniş bir tarih aralığına, daha büyük bir varsayılan kesirli kesinliğe ve isteğe bağlı isteğe bağlı kullanıcı kesinliğine sahiptir. Ayrıca kullanıcı tarafından belirlenen hassasiyete bağlı olarak daha az depolama alanı kullanabilir. 

557
Adam Porad

DATETIME2, "0001/01/01" ile "9999/12/31" arasındaki bir tarih aralığına sahipken, DATETIME türü yalnızca 1753-9999 yılını destekler.

Ayrıca, gerekirse, DATETIME2, zaman açısından daha kesin olabilir; DATETIME, 3 1/3 milisaniye ile sınırlıdır; DATETIME2, 100ns'a kadar doğru olabilir.

Her iki tür de .NET'te System.DateTime ile eşlenir - fark yoktur.

Seçeneğiniz varsa, mümkün olduğunda DATETIME2 kullanmanızı öneririz. DATETIME kullanarak herhangi bir fayda göremiyorum (geriye dönük uyumluluk hariç) - daha az sorun yaşarsınız (tarihler aralık dışında ve bunun gibi güçlüklerle).

Artı: sadece tarihe ihtiyacınız varsa (zaman bölümü olmadan), DATE kullanın - bu da DATETIME2 kadar iyidir ve size yer kazandırır! :-) Aynı şey sadece zaman için geçerli - TIME öğesini kullanın. Bu tipler bunun için var!

454
marc_s

datetime2, çoğu durumda kazanır (eski uygulamalar Uyumluluk)

  1. daha büyük değer aralığı 
  2. daha iyi Doğruluk
  3. daha küçük depolama alanı (isteğe bağlı kullanıcı tarafından belirlenen hassasiyet belirtilmişse)

SQL Date and time data types compare - datetime,datetime2,date,TIME

lütfen aşağıdaki hususlara dikkat edin

  • Sözdizimi
    • datetime2 [(kesirli saniye hassasiyeti => Depolama Boyutunun Altına Bak)]
  • Hassas ölçek
    • 0 ila 7 hane, 100ns doğrulukta. 
    • Varsayılan hassasiyet 7 hanedir.
  • Depolama Birimi
    • 3'ten az hassasiyet için 6 bayt; 
    • Hassas 3 ve 4 için 7 bayt. 
    • Diğer tüm hassasiyetler 8 bayt gerektirir.
  • DateTime2 (3), DateTime ile aynı sayıda haneye sahipse de, 8 bayt yerine 7 baytlık depolama alanı kullanır ( SQLHINTS- DateTime Vs DateTime2 )
  • Daha fazla bilgi için datetime2 (Transact-SQL MSDN makalesi)

image source: MCTS Kendiliğinden Eğitim Eğitim Seti (Sınav 70-432): Microsoft® SQL Server® 2008 - Uygulama ve Bakım .__ Bölüm 3: Tablolar -> Ders 1: Tablolar Oluşturma - > sayfa 66

175
Iman Abidi

@Marc_s ve @Adam_Poward ile aynı fikirde oldum - DateTime2, ilerlemeye tercih edilen yöntemdir. Daha geniş bir tarih aralığına, daha yüksek hassasiyete sahiptir ve eşit veya daha az depolama alanı kullanır (kesinliğe bağlı olarak). 

Tartışmanın kaçırdığı bir şey var, ancak ...
@ Marc_s durumları: Both types map to System.DateTime in .NET - no difference there. Bu doğrudur, bununla birlikte, tersi doğru değildir ... ve tarih aralığı aramaları yaparken önemlidir (örneğin, "5/5/2010 tarihinde değiştirilmiş tüm kayıtları bul"). 

.NET'in Datetime sürümü, DateTime2 ile benzer aralık ve hassasiyete sahiptir. Bir .net Datetime dosyasını eski SQL DateTime ile eşleştirirken, örtülü bir yuvarlama gerçekleşir. Eski SQL DateTime 3 milisaniye için doğrudur. Bu, 11:59:59.997 'un günün sonuna kadar mümkün olduğu kadar yakın olduğu anlamına gelir. Daha yüksek olan her şey ertesi güne yuvarlanır.

Bunu dene :

declare @d1 datetime   = '5/5/2010 23:59:59.999'
declare @d2 datetime2  = '5/5/2010 23:59:59.999'
declare @d3 datetime   = '5/5/2010 23:59:59.997'
select @d1 as 'IAmMay6BecauseOfRounding', @d2 'May5', @d3 'StillMay5Because2msEarlier'

Bu örtülü yuvarlamadan kaçınmak, DateTime2'ye geçmenin önemli bir nedenidir. Örtük tarihlerin yuvarlanması açıkça karışıklığa neden olur:

102
EBarr

DateTime2, söz konusu alana Now () yazmayı deneyen bir Access geliştiricisi iseniz mahvetti Bir Access -> SQL 2008 R2 geçişi gerçekleştirdi ve tüm tarih saatlerini DateTime2 olarak ekledi. Değer bombalanırken Now () ile bir kayıt ekleme. 01.01.2012 14:53:04 PM, fakat 1/10/2012 02:53:04 

Bir kez karakter fark yarattı. Umarım birine yardım eder.

15
Rhett A Brown

İşte size depolama büyüklüğü (bayt) ve smalldatetime, datetime, datetime2 (0) ve datetime2 (7) arasındaki hassasiyetteki farklılıkları gösterecek bir örnek:

DECLARE @temp TABLE (
    sdt smalldatetime,
    dt datetime,
    dt20 datetime2(0),
    dt27 datetime2(7)
)

INSERT @temp
SELECT getdate(),getdate(),getdate(),getdate()

SELECT sdt,DATALENGTH(sdt) as sdt_bytes,
    dt,DATALENGTH(dt) as dt_bytes,
    dt20,DATALENGTH(dt20) as dt20_bytes,
    dt27, DATALENGTH(dt27) as dt27_bytes FROM @temp

hangi döner

sdt                  sdt_bytes  dt                       dt_bytes  dt20                 dt20_bytes  dt27                         dt27_bytes
2015-09-11 11:26:00  4          2015-09-11 11:25:42.417  8         2015-09-11 11:25:42  6           2015-09-11 11:25:42.4170000  8

Bu yüzden eğer bilgileri ikinciye kaydetmek istersem - ama milisaniyeye değil - tarihsaat veya tarihsaat2 (7) yerine datetime2 (0) kullanırsam her birini 2 byte tasarruf edebilirim.

13
Baodad

Hemen hemen tüm Cevaplar ve Yorumlar Artıları ve Eksileri aydınlatıyordu. İşte şimdiye kadar ki tüm Artıları ve Eksileri özetinin yanı sıra bazı önemli Eksileri (aşağıda 2 numaralı) yalnızca bir kez veya hiç belirtilmediğini gördüm.

  1. Artıları:

1.1. Daha fazla ISO uyumlu (ISO 8601) (bunun pratikte nasıl devreye girdiğini bilmeme rağmen).

1.2. Daha fazla aralık (1/1/0001 - 12/31/9999 vs. 1/1/1753-12/31/9999) (her ne kadar 1753’den önceki tüm ekstralar büyük olasılıkla kullanılmayacaksa da, Tarihi, astronomik, jeolojik vb. uygulamalar).

1.3. Tam olarak .NET’in DateTime Type’ın aralığıyla eşleşiyor (değerler hedef türün aralığındaysa, her ikisi de özel kodlama olmadan ileri ve geri dönüşüme rağmen, hata veya yuvarlama gerçekleşir.

1.4. Daha fazla hassasiyet (100 nanosaniye aka 0.000.000, 1, vs. 3.33 milisaniye, diğer bir deyişle 0.003, 33 saniye) (ekstra hassasiyet muhtemelen mühendislik/bilimsel uygulamalarda haricinde kullanılmayacak olmasına rağmen).

1.5. Benzer için yapılandırıldığında (1 milisaniyede olduğu gibi "Iman Abidi'nin iddia ettiği gibi 3.33 milisaniyede" değil) DateTime hassasiyetiyle, daha az yer kullanır (7 - 8 bayt), ancak tabii ki, Muhtemelen gereksiz yararlar da olsa, en fazla lanse olan iki kişiden biri (diğeri menzilli) olan hassasiyet avantajını kaybediyor olacaktı.

  1. EKSİLERİ: 

2.1. Bir Parametreyi bir .NET SqlCommand öğesine geçirirken, SQL Server DateTime 'ın alanı ve/veya kesinliği dışında bir değer geçiriyorsanız System.Data.SqlDbType.DateTime2 belirtmelisiniz, çünkü varsayılan olarak System.Data.SqlDbType.DateTime' a varsayılandır.

2.2. Sayısal değerleri ve işleçleri kullanarak SQL Server ifadelerinde aşağıdakileri yapmak üzere/ile kayan nokta sayısal değerine (minimum tarih-saatten sonraki gün sayısı) değerine dolaylı/kolayca dönüştürülemez:

2.2.1. gün sayısını veya kısmi günleri ekleyin veya çıkarın. Not: Geçici çözüm olarak DateAdd işlevini kullanma Tarih tarihinin tüm bölümleri değilse, birden fazla dikkate almanız gerektiğinde önemsiz değildir.

2.2.2. “yaş” hesaplaması amacıyla iki tarih-saat arasındaki farkı alınız. Not: Bunun yerine, yalnızca SQL Server'ın DateDiff İşlevini kullanamazsınız, çünkü çoğu kişi age değerini hesaplamaz çünkü iki tarih-saat bir süre için belirtilen birimlerin takvim/saat tarih-saat sınırını geçerse bunun olmasını bekler. Bu birimin çok küçük bir kısmı, o, o birimin 1'e karşılık 0'ındaki farkı döndürür. Örneğin, DateDiff içindeki Day 'ın iki tarih-saatindeki yalnızca 1 milisaniyelik aralık, eğer 1 - 0 (gün) ise 1 - geri döner. saatler farklı takvim günlerindedir (örneğin “1999-12-31 23: 59: 59.9999999” ve “2000-01-01 00: 00: 00.0000000”). Aynı 1 milisaniyelik fark, bir takvim gününü geçmeyecek şekilde taşınırsa, tarih-saat farkı, Day 'ın 0 (gün) olarak bir "DateDiff" döndürür.

2.2.3. önce “Float” a, sonra tekrar Avg'e dönüştürerek (Toplam Sorguda) DateTime tarihini (Toplam Sorguda) alın.

NOT: DateTime2 değerini bir sayısal sayıya dönüştürmek için, değerlerinin 1970 yılından daha az olmadığını varsayan aşağıdaki formüle benzer bir şey yapmanız gerekir (bu, tüm ekstra aralığı artı 217 yıl daha kaybettiğiniz anlamına gelir. sayısal taşma sorunlarıyla karşılaşabileceğiniz için ekstra aralığa izin verecek şekilde formülü basitçe ayarlayamayabilir.

25567 + (DATEDIFF(SECOND, {d '1970-01-01'}, @Time) + DATEPART(nanosecond, @Time) / 1.0E + 9) / 86400.0 - Kaynak: “ https://siderite.blogspot.com/2015/08/how-to-translate-t-sql-datetime2-to.html

Tabii ki, ayrıca Cast - DateTime için ilk önce (ve gerekirse tekrar DateTime2'a geri dönebilirsiniz), ancak DateTime2 ile DateTime'nin hassasiyetini ve aralığını (1753 yılından önceki tüm) faydalarını kaybedersiniz. Aynı zamanda, ekleme/çıkarma/"yaş" (vs. DateDiff)/Avg için kayan nokta sayısal (gün sayısı) şeklinde örtük/kolay dönüşümleri kaybettiğinizde neden kullandığınız sorusunu soran en az 2 muhtemel ihtiyacı da belirtiniz. Tecrübelerime göre büyük olan, hesaplanan fayda.

Ancak, tarih zamanlarının Avg önemli bir kullanım durumudur (veya en azından olmalıdır). a) Tarih-zamanlar (ortak bir temel tarih-zamandan beri) süreyi (ortak bir uygulama) göstermek için kullanıldığında ortalama sürenin kullanılmasının yanı sıra, b) ortalama tarihin ne olduğuna dair bir gösterge tablosu tipi istatistik elde etmek de yararlıdır. saat, bir aralık/Satır grubunun tarih-saat sütununda bulunur. c) Standart (veya en azından [ standart olmalıdır) geçici Bir sütunda, artık/daha uzun süre geçerli olmayabilecek ve/veya kullanımdan kaldırılması gerekebilecek değerleri izlemek/sorun gidermek için bir sorgu yapın. oluşum sayısını ve (varsa), bu değerle ilişkili Min, Avg ve Max tarih-zaman damgalarını değerleyin.

12
Tom

ABD dışındaki datetime ayarları kullanıldığında, tarih dizgilerinin DATEFORMAT ve datetime2 olarak yorumlanması farklı olabilir. Örneğin.

set dateformat dmy
declare @d datetime, @d2 datetime2
select @d = '2013-06-05', @d2 = '2013-06-05'
select @d, @d2

Bu, datetime için 2013-05-06 (yani 6 Mayıs) ve 2013-06-05 için datetime2 (yani 5 Haziran) döndürür. Ancak, dateformat, mdy olarak ayarlandıysa, hem @d hem de @d22013-06-05 değerini döndürür.

datetime davranışı, aşağıdakileri ifade eden SET DATEFORMAT dosyasının MSDN belgelerini ile çelişmektedir: Bazı karakter dizeleri biçimleri, örneğin ISO 8601, bağımsız olarak yorumlanır. DATEFORMAT ayarı . Açıkçası doğru değil!

Bununla ısırılıncaya kadar, her zaman yyyy-mm-dd tarihlerinin, dil/yerel ayarlardan bağımsız olarak doğru yapıldığını düşünürdüm.

9
Richard Fawcett

kesinlik _ ​​ datetime2 ile artmışken, bazı istemciler date, time veya datetime2 'ı desteklemiyor ve sizi bir dizeye dönüştürmeye zorluyor değişmezi. Özellikle Microsoft, "aşağı seviye" ODBC, OLE DB, JDBC ve SqlClient sorunlarından söz eder ve bu veri türleriyle ilgili her birinin türü nasıl eşleyebileceğini gösteren bir çizelgesi vardır. 

Değer uygunluk hassasiyetin üzerindeyse, datetime kullanın

8
FistOfFury

Eski Soru ... Ama burada kimse tarafından henüz belirtilmemiş bir şey eklemek istiyorum ... (Not: Bu benim kendi gözlemim, bu yüzden herhangi bir referans istemeyin)

Datetime2, filtre ölçütlerinde kullanıldığında daha hızlıdır.

TLDR:

SQL 2016'da, yüz bin satır ve ENTRY_TIME tarih tarihli bir sütuna sahip bir masam vardı çünkü kesin zamanı saniyeler öncesine kadar saklamam gerekiyordu. Pek çok birleşim ve bir alt sorgu içeren karmaşık bir sorgu yürütürken, nerede yan tümce kullanıldığında:

WHERE ENTRY_TIME >= '2017-01-01 00:00:00' AND ENTRY_TIME < '2018-01-01 00:00:00'

Sorgu başlangıçta yüzlerce satır olduğunda iyiydi, ancak satır sayısı arttığında, sorgu bu hatayı vermeye başladı:

Execution Timeout Expired. The timeout period elapsed prior
to completion of the operation or the server is not responding.

Where yan tümcesini kaldırdım ve beklenmedik bir şekilde, sorgu 1 sn'de çalıştırıldı, ancak tüm tarihler için TÜM satırlar alındı. İçsel sorguyu nerede yan tümce ile çalıştırdım ve 85 saniye sürdü ve yan tümce olmadan 0.01 saniye sürdü.

Bu konuda bir çok konu ile karşılaştım/ tarih filtreleme performansı

Sorgu biraz optimize ettim. Ama aldığım asıl hız datetime sütununu datetime2 olarak değiştirmekti.

Şimdi daha önce zaman aşımına uğramış aynı sorgu bir saniyeden daha az sürer.

şerefe

5
Khan

bu maddeye göre , DateTime2 kullanarak aynı DateTime hassasiyetine sahip olmak istiyorsanız, sadece DateTime2 (3) kullanmak zorundasınız. Bu size aynı hassasiyeti vermeli, daha az byte atmalı ve genişletilmiş bir aralık sağlamalıdır. 

4
jKlaus

Ben sadece DATETIME2 için bir avantaj daha tökezledi: Python adodbapi modülünde, datetime sütunu için sıfır olmayan mikrosaniye sahip, ancak ____di değişken__ sütunu için standart olmayan bir kütüphane DATETIME değeri geçilirse patlayan bir hata önlenir DATETIME2.

3
Bob Kline
Select ValidUntil + 1
from Documents

Yukarıdaki SQL bir DateTime2 alanıyla çalışmaz . Döndürür ve "Operand type clash: datetime2 int ile uyumlu değil" hatası veriyor.

Ertesi günü almak için 1 eklemek, geliştiricilerin yıllardır tarihlerle birlikte yaptıkları bir şeydir. Şimdi Microsoft, bu basit işlevselliği yerine getiremeyen süper yeni bir datetime2 alanına sahip.

"Eskiden daha kötü olan bu yeni türü kullanalım", sanmıyorum!

0
Paul McCarthy

Bence DATETIME2, tarihi depolamak için daha iyi bir yol çünkü bence DATETIME'dan daha verimli. SQL Server 2008'de DATETIME2 kullanabilirsiniz, tarih ve saati depolar, saklamak için 6-8 bayt alır ve 100 nanosaniye hassasiyete sahiptir. Böylece daha fazla zaman hassasiyetine ihtiyaç duyan herkes DATETIME2'yi isteyecektir.

0
James