簡體   English   中英

SQL 服務器中的 DateTime2 與 DateTime

[英]DateTime2 vs DateTime in SQL Server

哪一個:

是在 SQL Server 2008+ 中存儲日期和時間推薦方法嗎?

我知道精度(可能還有存儲空間)的差異,但是暫時忽略這些,是否有關於何時使用什么的最佳實踐文檔,或者我們應該只使用datetime2嗎?

datetime的 MSDN 文檔建議使用datetime2 這是他們的建議:

為新工作使用timedatedatetime2datetimeoffset數據類型。 這些類型符合 SQL 標准。 它們更便攜。 timedatetime2datetimeoffset提供更多秒精度。 datetimeoffset為全球部署的應用程序提供時區支持。

datetime2 具有更大的日期范圍、更大的默認小數精度和可選的用戶指定精度。 此外,根據用戶指定的精度,它可能會使用較少的存儲空間。

DATETIME2的日期范圍為“0001 / 01 / 01”到“9999 / 12 / 31”,而DATETIME類型僅支持 1753-9999 年。

此外,如果需要, DATETIME2可以在時間方面更精確; DATETIME 被限制為 3 1/3 毫秒,而DATETIME2可以精確到 100ns。

兩種類型都映射到 .NET 中的System.DateTime - 沒有區別。

如果您有選擇,我建議您盡可能使用DATETIME2 我沒有看到使用DATETIME任何好處(除了向后兼容性) - 你會遇到更少的麻煩(日期超出范圍和麻煩)。

另外:如果您只需要日期(沒有時間部分),請使用 DATE - 它與DATETIME2一樣好,也可以節省空間! :-) 同樣適用於時間 - 使用TIME 這就是這些類型的用途!

datetime2在大多數方面都勝出(舊應用程序兼容性)

  1. 更大范圍的值
  2. 更好的准確性
  3. 更小的存儲空間(如果指定了可選的用戶指定精度)

SQL 日期和時間數據類型比較 - datetime,datetime2,date,TIME

請注意以下幾點

  • 句法
    • datetime2[(小數秒精度=> 看下面的存儲大小)]
  • 精度、規模
    • 0~7位,精度100ns。
    • 默認精度為 7 位。
  • 存儲大小
    • 精度小於 3 時為 6 個字節;
    • 7 個字節用於精度 3 和 4。
    • 所有其他精度都需要 8 個字節
  • DateTime2(3)具有與 DateTime 相同的位數,但使用 7 個字節的存儲空間而不是 8 個字節( SQLHINTS-DateTime Vs DateTime2
  • datetime2上查找更多信息(Transact-SQL MSDN 文章)

圖片來源: MCTS 自定進度培訓套件(考試 70-432):Microsoft® SQL Server® 2008 - 實施和維護第 3 章:表 -> 第 1 課:創建表 -> 第 66 頁

我同意@marc_s 和@Adam_Poward——DateTime2 是前進的首選方法。 它的日期范圍更廣,精度更高,並且使用相等或更少的存儲空間(取決於精度)。

然而,討論遺漏了一件事......
@Marc_s 聲明: Both types map to System.DateTime in .NET - no difference there 這是正確的,然而,反之則不正確……這在進行日期范圍搜索時很重要(例如“找到我在 2010 年 5 月 5 日修改的所有記錄”)。

.NET 的Datetime版本具有與DateTime2相似的范圍和精度。 將 .net Datetime向下映射到舊的 SQL DateTime Datetime時,會發生隱式舍入 舊的 SQL DateTime精確到 3 毫秒。 這意味着11:59:59.997盡可能接近一天的結束。 任何更高的值都會向上舍入到第二天。

嘗試這個 :

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'

避免這種隱式舍入是轉移到 DateTime2 的重要原因。 日期的隱式四舍五入顯然會導致混淆:

幾乎所有的答案和評論都強調了優點,而強調了缺點。 這是迄今為止所有優點和缺點的回顧,以及一些關鍵的缺點(在下面的 #2 中)我只見過一次或根本沒有提到。

  1. 優點:

1.1. 更符合 ISO (ISO 8601)(雖然我不知道這在實踐中是如何發揮作用的)。

1.2. 更多的范圍(1/1/0001 到 12/31/9999 vs. 1/1/1753-12/31/9999)(盡管額外的范圍,都在 1753 年之前,可能不會被使用,除了例如,在歷史、天文、地質等應用程序中)。

1.3. 完全匹配 .NET 的DateTime類型的范圍(盡管如果值在目標類型的范圍和精度內,則兩者都沒有特殊編碼來回轉換,除了下面的 Con # 2.1 否則會發生錯誤/舍入)。

1.4. 更高的精度(100 納秒又名 0.000,000,1 秒 vs. 3.33 毫秒,又名 0.003,33 秒)(盡管可能不會使用額外的精度,除非在工程/科學應用中除外)。

1.5. 當配置為類似(如 Iman Abidi 聲稱的 1 毫秒不“相同”(如 3.33 毫秒))精度為DateTime ,使用更少的空間(7 對 8 字節),但當然,你會失去精度好處可能是最受吹捧的兩個(另一個是范圍)之一,盡管可能是不需要的好處)。

  1. 缺點:

2.1. 將參數傳遞給 .NET SqlCommand ,如果您傳遞的值可能超出 SQL Server DateTime的范圍和/或精度,則必須指定System.Data.SqlDbType.DateTime2 ,因為它默認為System.Data.SqlDbType.DateTime

2.2. 不能隱式/輕松轉換為浮點數字(自最小日期時間以來的天數)值,以便在使用數字值和運算符的 SQL Server 表達式中對其執行以下操作:

2.2.1. 添加或減去天數或部分天數。 注意:當您需要考慮日期時間的多個部分(如果不是全部)時,使用DateAdd函數作為解決方法並DateAdd

2.2.2. 出於“年齡”計算的目的,取兩個日期時間之間的差異。 注意:您不能簡單地使用 SQL Server 的DateDiff函數,因為它不會像大多數人所期望的那樣計算age ,因為如果兩個日期時間恰好跨越指定單位的日歷/時鍾日期時間邊界,即使對於一個該單位的一小部分,它將返回該單位的 1 與 0 的差異。例如,如果兩個日期時間相隔僅 1 毫秒, DayDateDiff將返回 1 與 0(天),如果這些日期時間在不同的日歷日(即“1999-12-31 23:59:59.9999999”和“2000-01-01 00:00:00.0000000”)。 如果移動相同的 1 毫秒差異日期時間,以便它們不會跨越日歷日,則將在Day 's of 0(天)中返回“DateDiff”。

2.2.3. 通過簡單地首先轉換為“Float”然后再轉換回DateTime來獲取日期時間的Avg (在聚合查詢中)。

注意:要將DateTime2轉換為數字,您必須執行類似於以下公式的操作,該公式仍然假定您的值不小於 1970 年(這意味着您將失去所有額外范圍加上另外 217 年。注意:您可能無法簡單地調整公式以允許額外的范圍,因為您可能會遇到數字溢出問題。

25567 + (DATEDIFF(SECOND, {d '1970-01-01'}, @Time) + DATEPART(nanosecond, @Time) / 1.0E + 9) / 86400.0 – 來源:“ https://siderite.dev/blog /how-to-translate-t-sql-datetime2-to.html

當然,你也可以CastDateTime第一(如果必要,再次回到DateTime2 ),但你會失去精度和范圍(全年開放前1753)的好處DateTime2DateTime這是prolly 2最大,也同時prolly 2個最不可能需要的問題,當您丟失隱式/簡單轉換為浮點數字(天數)以進行加法/減法/“年齡”(與DateDiff )/ Avg時,為什么要使用它calcs 的好處在我的經驗中是一個很大的好處。

順便說一句,日期時間的Avg是(或至少應該是)一個重要的用例。 a) 除了在日期時間(因為一個共同的基准日期時間)用於表示持續時間(一種常見做法)時用於獲取平均持續時間,b)獲取關於平均日期的儀表板類型統計數據也很有用 -時間在一個范圍/一組行的日期時間列中。 c) 一個標准(或至少應該是標准的)臨時查詢來監視/排除列中可能永遠/不再有效和/或可能需要棄用的值是為每個值列出出現計數以及(如果可用)與該值關聯的MinAvgMax日期時間戳。

下面是一個示例,它將向您展示 smalldatetime、datetime、datetime2(0) 和 datetime2(7) 在存儲大小(字節)和精度方面的差異:

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

返回

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

因此,如果我想將信息存儲到秒 - 但不是毫秒 - 如果我使用 datetime2(0) 而不是 datetime 或 datetime2(7),我可以節省 2 個字節。

如果您是嘗試將 Now() 寫入相關字段的 Access 開發人員,則 DateTime2 會造成嚴重破壞。 剛剛做了一個 Access -> SQL 2008 R2 遷移,它把所有的日期時間字段作為 DateTime2。 使用 Now() 附加一條記錄作為值被炸毀。 2012 年 1 月 1 日下午 2:53:04 沒問題,但 2012 年 1 月 10 日下午 2:53:04 不行。

一旦性格有所不同。 希望它可以幫助某人。

老問題……但我想補充一些這里沒有人說過的東西……(注:這是我自己的觀察,所以不要要求任何參考)

Datetime2 在過濾條件中使用時更快。

域名注冊地址:

在 SQL 2016 中,我有一個包含十萬行和一個日期時間列 ENTRY_TIME 的表,因為它需要存儲精確到秒的時間。 在執行具有許多連接和子查詢的復雜查詢時,當我使用 where 子句時:

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

當有數百行時,查詢最初很好,但是當行數增加時,查詢開始出現此錯誤:

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

我刪除了 where 子句,出乎意料的是,查詢在 1 秒內運行,盡管現在獲取了所有日期的所有行。 我使用 where 子句運行內部查詢,耗時 85 秒,沒有 where 子句則耗時 0.01 秒。

我在這里遇到了許多線程作為日期時間過濾性能

我稍微優化了查詢。 但是我獲得的真正速度是將日期時間列更改為 datetime2。

現在,之前超時的相同查詢只需不到一秒鍾。

干杯

當使用非美國DATEFORMAT設置時,將日期字符串解釋為datetimedatetime2也可能不同。 例如

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

這將返回2013-05-06 (即 5 月 6 日)的datetime2013-06-05 (即 6 月 5 日)的datetime2 然而, dateformat設置為mdy ,既@d@d2回報2013-06-05

datetime行為似乎與SET DATEFORMATMSDN 文檔不一致,該文檔指出:某些字符串格式,例如 ISO 8601,獨立於 DATEFORMAT 設置進行解釋 顯然不是真的!

直到我被這個咬到之前,我一直認為yyyy-mm-dd日期會被正確處理,無論語言/區域設置如何。

雖然datetime2提高了精度,但某些客戶端不支持datetimedatetime2並強制您轉換為字符串文字。 具體而言,Microsoft 提到了這些數據類型的“下層”ODBC、OLE DB、JDBC 和 SqlClient 問題,並有一個圖表顯示了每個類型如何映射類型。

如果值兼容性超過精度,請使用日期時間

根據這篇文章,如果您想使用 DateTime2 獲得與 DateTime 相同的精度,您只需使用 DateTime2(3)。 這應該給你相同的精度,少占用一個字節,並提供一個擴展的范圍。

我只是偶然發現了DATETIME2另一個優勢:它避免了 Python adodbapi模塊中的錯誤,如果傳遞標准庫datetime值,該值會adodbapi ,該值對於DATETIME列具有非零微秒,但如果該列定義為DATETIME2

由於其他答案顯示datetime2由於較小的尺寸和更高的精度而被推薦,但這里有一些關於為什么不使用 Nikola Ilic 的 datetime2 的想法:

  • 缺乏(簡單)使用日期進行基本數學運算的可能性,例如GETDATE()+1
  • 每次與DATEADDDATEDIFF進行比較時,您都將完成隱式數據轉換為datetime
  • SQL Server 無法正確使用 Datetime2 列的統計信息,因為數據的存儲方式會導致非最佳查詢計划,從而降低性能

我認為DATETIME2是存儲date的更好方法,因為它比DATETIME更有效率。 SQL Server 2008您可以使用DATETIME2 ,它存儲日期和時間,需要 6-8 bytes來存儲,精度為100 nanoseconds 所以任何需要更高時間精度的人都會想要DATETIME2

接受的答案很好,只要知道如果您向前端發送 DateTime2 - 它就會四舍五入為正常的 DateTime 等效值。

這給我帶來了一個問題,因為在我的解決方案中,我必須將重新提交時發送的內容與數據庫中的內容進行比較,而我的簡單比較“==”不允許四舍五入。 所以必須加上。

datetime2更好

  • datetime 范圍:1753-01-01 到 9999-12-31,datetime2 范圍:0001-01-01 到 9999-12-31

  • datetime 精度:0.00333 秒,datetime2 精度:100 納秒

  • datetime 得到 8 個字節,datetime2 得到 6 到 8 個字節取決於精度

    (精度小於3為6字節,精度3或4為7字節,其他精度需要8字節,點擊看下圖)

在此處輸入圖像描述

Select ValidUntil + 1
from Documents

上述 SQL 不適用於 DateTime2 字段。 它返回錯誤“操作數類型沖突:datetime2 與 int 不兼容”

添加 1 以獲得第二天是開發人員多年來一直在做的事情。 現在微軟有一個超級新的 datetime2 字段,它無法處理這個簡單的功能。

“讓我們使用這種比舊的更糟糕的新類型”,我不這么認為!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM