MySQL 中儲存時間的最佳實踐

又拍雲發表於2021-07-01

平時開發中經常需要記錄時間,比如用於記錄某條記錄的建立時間以及修改時間。在資料庫中儲存時間的方式有很多種,比如 MySQL 本身就提供了日期型別,比如 DATETIME,TIMESTAMEP 等,我們也可以直接儲存時間戳為 INT 型別,也有人直接將時間儲存為字串型別。

那麼到底哪種儲存時間的方式更好呢?

不要使用字串儲存時間型別

這是初學者很容易犯的錯誤,容易直接將欄位設定為 VARCHAR 型別,儲存"2021-01-01 00:00:00"這樣的字串。當然這樣做的優點是比較簡單,上手快。

但是極力不推薦這樣做,因為這樣做有兩個比較大的問題:

  • 字串佔用的空間大

  • 這樣儲存的欄位比較效率太低,只能逐個字元比較,無法使用 MySQL 提供的日期API

MySQL 中的日期型別

MySQL 資料庫中常見的日期型別有 YEAR、DATE、TIME、DATETIME、TIMESTAMEP。因為一般都需要將日期精確到秒,其中比較合適的有DATETIME,TIMESTAMEP。

DATETIME

DATETIME 在資料庫中儲存的形式為:YYYY-MM-DD HH:MM:SS,固定佔用 8 個位元組。

從 MySQL 5.6 版本開始,DATETIME 型別支援毫秒,DATETIME(N) 中的 N 表示毫秒的精度。例如,DATETIME(6) 表示可以儲存 6 位的毫秒值。

TIMESTAMEP

TIMESTAMP 實際儲存的內容為‘1970-01-01 00:00:00’到現在的毫秒數。在 MySQL 中,由於型別 TIMESTAMP 佔用 4 個位元組,因此其儲存的時間上限只能到‘2038-01-19 03:14:07’。

從 MySQL 5.6 版本開始,型別 TIMESTAMP 也能支援毫秒。與 DATETIME 不同的是,若帶有毫秒時,型別 TIMESTAMP 佔用 7 個位元組,而 DATETIME 無論是否儲存毫秒資訊,都佔用 8 個位元組。

型別 TIMESTAMP 最大的優點是可以帶有時區屬性,因為它本質上是從毫秒轉化而來。如果你的業務需要對應不同的國家時區,那麼型別 TIMESTAMP 是一種不錯的選擇。比如新聞類的業務,通常使用者想知道這篇新聞釋出時對應的自己國家時間,那麼 TIMESTAMP 是一種選擇。Timestamp 型別欄位的值會隨著伺服器時區的變化而變化,自動換算成相應的時間,說簡單點就是在不同時區,查詢到同一個條記錄此欄位的值會不一樣。

TIMESTAMP 的效能問題

TIMESTAMP 還存在潛在的效能問題。

雖然從毫秒數轉換到型別 TIMESTAMP 本身需要的 CPU 指令並不多,這並不會帶來直接的效能問題。但是如果使用預設的作業系統時區,則每次通過時區計算時間時,要呼叫作業系統底層系統函式 __tz_convert(),而這個函式需要額外的加鎖操作,以確保這時作業系統時區沒有修改。所以,當大規模併發訪問時,由於熱點資源競爭,會產生兩個問題:

  • 效能不如 DATETIME:DATETIME 不存在時區轉化問題。

  • 效能抖動:海量併發時,存在效能抖動問題。

為了優化 TIMESTAMP 的使用,建議使用顯式的時區,而不是作業系統時區。比如在配置檔案中顯示地設定時區,而不要使用系統時區:

[mysqld]

time_zone = "+08:00"

簡單總結一下這兩種資料型別的優缺點:

  • DATETIME 沒有儲存的時間上限,而TIMESTAMP儲存的時間上限只能到‘2038-01-19 03:14:07’

  • DATETIME 不帶時區屬性,需要前端或者服務端處理,但是僅從資料庫儲存資料和讀取資料而言,效能更好

  • TIMESTAMP 帶有時區屬性,但是每次需要通過時區計算時間,併發訪問時會有效能問題

  • 儲存 DATETIME 比 TIMESTAMEP 多佔用一部分空間

數值型時間戳(INT)

很多時候,我們也會使用 int 或者 bigint 型別的數值也就是時間戳來表示時間。

這種儲存方式的具有 Timestamp 型別的所具有一些優點,並且使用它的進行日期排序以及對比等操作的效率會更高,跨系統也很方便,畢竟只是存放的數值。缺點也很明顯,就是資料的可讀性太差了,你無法直觀的看到具體時間。

如果需要檢視某個時間段內的資料

select * from t where created_at > UNIX_TIMESTAMP('2021-01-01 00:00:00');

DATETIME vs TIMESTAMP vs INT,怎麼選?

每種方式都有各自的優勢,下面再對這三種方式做一個簡單的對比:

TIMESTAMP 與 INT 本質一樣,但是相比而言雖然 INT 對開發友好,但是對 DBA 以及資料分析人員不友好,可讀性差。所以《高效能 MySQL 》的作者推薦 TIMESTAMP 的原因就是它的數值表示時間更加直觀。下面是原文:

至於時區問題,可以由前端或者服務這裡做一次轉化,不一定非要在資料庫中解決。

總結

本文比較了幾種最常使用的儲存時間的方式,我最推薦的還是 DATETIME。理由如下:

  • TIMESTAMP 比數值型時間戳可讀性更好

  • DATETIME 的儲存上限為 9999-12-31 23:59:59,如果使用 TIMESTAMP,則 2038 年需要考慮解決方案

  • DATETIME 由於不需要時區轉換,所以效能比 TIMESTAMP 好

  • 如果需要將時間儲存到毫秒,TIMESTAMP 要 7 個位元組,和 DATETIME 8 位元組差不太多

相關文章