寫這一篇是想到了當年對於時間的設計,還特地回頭翻了以前寫的文章 MongoDB 使用、設計時間欄位小心得。
又經過一年的磨練,對於之前的設計又有點想法想來聊聊。
起因
我們使用的語言是 .Net Core,設計的系統為跨國使用,因此時區問題是無法避免的。系統中一律使用 c# DateTimeOffset
,直接存進 MongoDB 會變成一個陣列(可以參考上面的連結),在查詢上會變得緩慢。
下一步改動就跳到了 c# 的 UtcTick
,這樣好處是儲存體都是 UTC 時間,對外溝通都一率使用 UTC,很符合我們的技術棧 gRPC (時間皆是用 timestamp)。很好的解決了當時的所有問題,反正客戶端在哪個時區,再進行轉換就好。
1 | Timestamp 是 Unix 時間,`1970年1月1日00:00:00 UTC` 為時間原點 |
魔鬼藏在細節裡
使用一段時間後,發現我們有個小困境,有些使用者情境不需要如此精確的時間,例如可能只以小時或者天為單位,所幸儲存體不算貴,因此一種時間就有了三個欄位:
1 | CreateTime (Ticks) |
這樣還是能解決我們大部分的商務需求。但某一天接到一個臨時性的支援需求,需要以某個時間欄位以天
為單位進行統計資料(GroupBy),這時我驚覺,這個我們做不到了,況且今天是以週、雙週、月為單位呢?是不是要存更多欄位但又很少使用到,實在很浪費。
反思設計
回頭看 MongoDB 提供哪些時間的儲存資料類別:
Data Type | PROS | CONS |
---|---|---|
Date | 精確度高 | 程式面需強制UTC |
Timestamp | 可無痛對外溝通 | 精確度不足 |
Long(Tick) | 數值型別比較快 | 1. 人類無法閱讀 2.無法在 MongoDB 做轉換 |
Array(DateTimeOffset) | 資料皆儲存到了 | 慢 |
String(DateString) | 別鬧了 | 別鬧了 |
透過上表,先來看看選手們:
- Timestamp: 缺點就是精准度不夠啦!如果需求面沒有到毫秒,我應該是會考慮使用,且還是可以在 MongoDB 做轉換。
- Long(Tick): 好,我必須承認這不是一個好的設計,很想獲得 Approve 進行整個系統大改進。Tick 除了無法閱讀,在查問題時需搭配網頁或工具貼來貼去的轉換,致命性問題就是無法調整精確度。
- Date: 提供高精確度,且可以在 MongoDB 進行轉換,無疑是最全面的資料型別了,至於效能部分,目前還不敢說與 Long 的差異,也許未來有機會再來測試。
- Array, String: 想都別想,真的。
結論
- 有毫秒需求=> MongoDB 使用 Date
- 無毫秒需求=>
- 系統有使用 Timestamp => MongoDB 使用 Timestamp
- 系統無使用 Timestamp => MongoDB 使用 Date
希望為後來設計新需求或是系統的人提供一點意見。