筆記目錄

Skip to content

淺談 SQL Server 日期時間查詢與精度進位陷阱

TLDR

  • 應全面棄用 datetimesmalldatetime,改用 datetime2 作為標準時間型別,以避免精度進位與範圍限制問題。
  • 建議明確指定資料庫欄位精度(如 datetime2(0)datetime2(3)),避免依賴框架預設值導致的遷移風險。
  • 進行時間區間查詢時,應一律採用 [開始時間] <= x < [結束時間] 的寫法,嚴禁使用 AddTicks(-1) 進行閉合區間處理。
  • 應用程式層應統一時間來源,避免在 SQL 語句中混用 GETDATE() 或進行複雜的時間運算,以確保 SARGability 並維持索引效能。
  • 當應用程式變數型別與資料庫欄位型別不一致時(如 datetime2 變數查詢 datetime 欄位),會觸發隱式轉換導致效能下降或查詢結果異常。

SQL Server 的日期時間型別選擇

在 SQL Server 2025 環境下,不同日期時間型別的特性如下表所示:

型別精度說明
datetime3.33 毫秒舊系統產物,毫秒非連續,會自動進位。
smalldatetime1 分鐘秒數會四捨五入進位至分,範圍僅至 2079 年。
datetime2100 奈秒新專案首選,精度高且範圍廣(0001-9999 年)。
datetimeoffset100 奈秒包含時區偏移量,適合跨國應用。

TIP

實務上,應優先選用 datetime2datetimeoffsetsmalldatetime 存在潛在的「千年蟲」風險,而 datetime 則因精度進位問題,已不建議在新開發中使用。此外,若需從 Oracle 遷移資料,datetime2 支援至 0001 年,能有效解決 datetime 僅支援至 1753 年導致的寫入失敗問題。

關於精度的選擇 (0)(3)(7)

  • 精度 (0) (秒):適用於不需要高精度顯示的場景,可避免前端顯示與後端儲存不一致導致的查詢失敗。
  • 精度 (3) (毫秒):業界通用標準,兼顧效能與解析度,適用於大多數高併發場景。
  • 精度 (7) (100 奈秒):與 C# DateTime.Ticks 一致,適用於科學運算或系統日誌。

WARNING

若使用 Entity Framework Code First,請務必顯式指定精度(例如 .HasPrecision(0)),切勿依賴框架預設值,以免未來升級或遷移時發生非預期的行為。

時間來源的統一性與效能考量

當系統採用高精度(如 (7))時,必須解決時間來源不一致的問題。若在應用程式多處重複呼叫 DateTime.Now,會因微小的時間差導致同一交易內的時間戳記不一致。

應用層 vs 資料庫層

建議將時間處理統一在應用程式層,並透過參數傳遞至資料庫。

  • 什麼情況下會遇到問題:當 SQL 語句中直接使用 GETDATE() 或對欄位進行運算(如 DATEADD(MINUTE, -1, RecordTime) = GETDATE())時,會導致 SARGability 失效,使索引搜尋(Index Seek)退化為索引掃描(Index Scan),嚴重影響效能。
csharp
// 建議寫法:在應用層取得時間後,作為參數傳入
DateTime now = DateTime.Now;
db.Table.Where(x => x.RecordTime == now);

時間區間的閉合處理陷阱

在處理時間區間查詢時,常見的錯誤作法是使用 AddTicks(-1) 來處理結束時間的閉合。

  • 什麼情況下會遇到問題:當資料庫欄位型別為 datetime,但應用程式變數為 datetime2 時,因兩者精度不同,AddTicks(-1) 的操作會產生進位誤差,導致查詢結果遺漏或包含非預期的資料。

推薦做法

應一律使用「左閉右開」的區間查詢,以確保語意清晰且具備通用性:

csharp
// ✅ 推薦寫法
db.Table.Where(x => x.Time >= input.StartTime && x.Time < input.EndTime);

精度進位導致的查詢異常

datetime 型別會將毫秒進位至 037。若宣告一個 datetime 變數為 '2026-02-10 07:59:59.999',SQL Server 會將其進位為 '2026-02-10 08:00:00.000',導致查詢條件與實際儲存值產生偏差。

datetime2-less-equal-parameterdatetime-less-equal-parameter

如上圖所示,當使用 <= 比較時,型別不一致會導致執行計畫出現顯著差異,進而影響查詢效能與正確性。

異動歷程

  • 2026-02-12 初版文件建立。