MongoDB 時間的資料欄位差異與優缺點

2022/09/30 Update
最近重新翻出這篇文章,覺得當初撰寫時有些不夠明確與細節,特地再更新一下內容


寫這一篇是想到了當年對於時間的設計,還特地回頭翻了以前寫的文章 MongoDB 使用、設計時間欄位小心得

又經過一年的磨練,對於之前的設計又有點想法想來聊聊。

起因

我們使用的語言是 .Net Core,設計的系統為跨國使用,因此時區問題是無法避免的。系統中一律使用 C# DateTimeOffset,直接存進 MongoDB 會變成一個陣列(可以參考上面的連結),除了使用上稍微不方便、時區功能也是無用的儲存(因為系統端通常都是無時區,到了呈現端才會轉換),在查詢上也會稍微有差距。

接著嘗試了 C# DateTime,進了 MongoDB 後就是 Date 格式,很好處理掉上面的問題,但另一個更致命的是,商業產品上對於毫秒的精確度很高,而 Date 最多只支援三位毫秒,完全不服使用情境。

最後選用了 C# 的 UtcTick,這樣好處是儲存體都是 UTC 時間,對外溝通都一率使用 UTC,很符合我們的技術棧 gRPC (時間皆是用 timestamp)。很好的解決了當時的所有問題,反正客戶端在哪個時區,再進行轉換就好; 最大的不便莫過於可讀性了,但暫時沒有更好的解決方案。

1
Timestamp 是 Unix 時間,`1970年1月1日00:00:00 UTC` 為時間原點

新需求新改變

使用一段時間後,發現我們有個小困境,有些使用者情境不需要如此精確的時間,例如可能只以小時或者天為單位,所幸儲存體不算貴,因此一種時間就有了三個欄位,分別都是 long 型別 (UTC Ticks):

1
2
3
CreateTime
CreateTimeHr
CreateTimeDate

這樣還是能解決我們大部分的商務需求。但某一天接到一個臨時性的支援需求,需要以某個時間欄位以為單位進行統計資料,這時我驚覺,這個我們做不到了!

以往使用時間型別,還能夠 TRUNCATE 格式在進行 GroupBy,純粹是 Tick 難度就變得非常高。未來若是遇上以週、雙週、月為單位呢?難道要存更多卻很少使用到的欄位?

反思設計

回頭看 MongoDB 提供哪些時間的儲存資料類別:

Data Type PROS CONS
Date 精確度高 程式面需強制UTC
Timestamp 可無痛對外溝通 精確度不足
Long(Tick) 1. 最精確 2.數值型別 1. 人類無法閱讀 2.無法在 MongoDB 做轉換
Array(DateTimeOffset) 有時區概念 較慢又用不到
String(DateString) 別鬧了 別鬧了

透過上表,先來看看選手們:

  • Timestamp: 缺點就是精准度不夠啦!如果需求面沒有到毫秒,我應該是會考慮使用,且還是可以在 MongoDB 做轉換。
  • Long(Tick): Tick 除了無法閱讀,在查問題時需搭配網頁或工具貼來貼去的轉換,致命性問題就是無法透過 MQL 調整精確度。
  • Date: 提供高精確度,且可以在 MongoDB 進行轉換,無疑是最全面的資料型別了,至於效能部分,目前還不敢說與 Long 的差異,也許未來有機會再來測試。
  • Array, String: 想都別想,真的。

結論

  • 超高精確度需求=> Ticks
  • 有毫秒需求=> 使用 Date
  • 無毫秒需求=>
    • 系統有使用 Timestamp => 用 Timestamp
    • 系統無使用 Timestamp => 使用 Date

希望為後來設計新需求或是系統的人提供一點意見。

  • 作者: MingYi Chou
  • 版權聲明: 轉載不用問,但請註明出處!本網誌均採用 BY-NC-SA 許可協議。