MySQL 保存日期,用哪種數(shù)據(jù)類型合適?datetime?timestamp?還是 int?
日期算是我們在日常開發(fā)中經常用到的數(shù)據(jù)類型,一般來說一張表都有 createTime 和 updateTime 字段,MySQL 中針對日期也提供了很多種不同的數(shù)據(jù)類型,如:
- datetime
- timestamp
- int
等等。甚至也有人直接將日期存為字符串的。
那么到底該用哪種類型來保存日期呢?
1. 字符串
在這些類型中,首先應該排除掉的就是字符串了,很多新手小伙伴愛用字符串存儲日期,但實際上這并不是一個很好的方案。
使用字符串存儲日期,第一個顯而易見的問題就是無法使用 MySQL 中提供的日期函數(shù),這會為很多查詢帶來不便。
例如用戶表中有一個字段 birthday,表示用戶的生日,現(xiàn)在想要查詢 2001 出生的所有用戶,如果 birthday 是 日期類型,就可以使用 YEAR 函數(shù),但是如果 birthday 是字符串類型,這個問題就不太好處理了。
使用字符串存儲日期的第二個問題就是占用空間較大,例如存儲如下時間:
2021-01-01 00:00:00
- 如果使用字符串,需要 19 個字節(jié)。
- 如果使用 datetime 需要 8 個字節(jié)。
- 如果使用 timestamp 需要 4 個字節(jié)。
所以首先排除掉字符串。
2. DATETIME VS TIMESTAMEP
2.1 占用空間
DATETIME 在數(shù)據(jù)庫中存儲的形式為:YYYY-MM-DD hh:mm:ss,至于占用的字節(jié)數(shù),則看情況,我們來看一段來自 MySQL 官網(wǎng)的內容:
可以看到,MySQL5.6.4 是一個分水嶺:
- 在 MySQL5.6.4 之前,DATETIME 固定占用 8 個字節(jié)。
- 從 MySQL5.6.4 開始,DATETIME 類型開始支持毫秒,DATETIME(N) 中的 N 表示毫秒的精度,例如,DATETIME(6) 表示可以存儲 6 位的毫秒值,那么此時,DATETIME 占用的字節(jié)數(shù),就跟后面的毫秒數(shù)有關了,如果 DATETIME 沒有詳細到毫秒,那么占用 5 個字節(jié),如果詳細到毫秒了,那就看情況,根據(jù)毫秒的精度,占用不同的空間,毫秒精度小于等于 2 時,總共占用 6 個字節(jié);毫秒精度小于等于 4 時,總共占用 7 個字節(jié);毫秒精度小于等于 6 時,總共占用 8 個字節(jié)。
同樣,由上圖我們也可以看出,在 MySQL5.6.4 之前,TIMESTAMEP 固定占用 4 個字節(jié),從 MySQL5.6.4 開始,依據(jù)毫秒的精度,TIMESTAMEP 占用的字節(jié)數(shù)介于 4 到 7 之間。
所以無論是 TIMESTAMEP,還是 DATETIME,都是比字符串節(jié)省空間的。
2.2 存儲范圍
DATETIME 的存儲范圍介于 1000-01-01 00:00:00 到 9999-12-31 23:59:59 之間。
TIMESTAMP 的存儲范圍則介于 1970-01-01 00:00:01 UTC 到 2038-01-19 03:14:07 UTC 之間。
很明顯 DATETIME 的存儲范圍要更大一些。
2.3 底層存儲TIMESTAMP 類型最大的優(yōu)勢在于自帶時區(qū)屬性,因為它本質上是從毫秒轉化而來。如果你的業(yè)務需要對應不同的國家時區(qū),那么類型 TIMESTAMP 是一種不錯的選擇,TIMESTAMP 類型字段的值會隨著服務器時區(qū)的變化而變化,自動換算成相應的時間,說簡單點就是在不同時區(qū),查詢到同一個條記錄此字段的值會不一樣。
舉個 TIMESTAMP 的使用場景例子:
新聞類的業(yè)務,通常用戶想知道這篇新聞發(fā)布時對應的自己國家時間,那么 TIMESTAMP 是一種不錯的選擇。
TIMESTAMP 會隨著時區(qū)的變化而自動調整,而 DATETIME 不會。
我舉個例子:假設我數(shù)據(jù)庫目前的時區(qū)是 Asia/Shanghai:
現(xiàn)在有一個 user 表,數(shù)據(jù)如下:
其中,createTime 字段是 DATETIME,而 updateTime 是 TIMESTAMP,現(xiàn)在我修改一下數(shù)據(jù)庫時區(qū),我們再來查看:
小伙伴們可以看到,我把時區(qū)設置為東京,東京比我們快一個小時,此時 updateTime 自動變了,而 DATETIME 不變。
時區(qū)的問題一定要謹慎,不過時區(qū)問題也并非一定要在數(shù)據(jù)庫中解決,也可以在前端或者服務端用代碼處理下。
2.4 性能比較
從毫秒數(shù)轉換到 TIMESTAMP 并不費事,但是當要進行時區(qū)轉換的時候,需要調用操作系統(tǒng)底層系統(tǒng)函數(shù),而這個函數(shù)需要額外的加鎖操作,以確保這時操作系統(tǒng)時區(qū)沒有修改,一加鎖,效率就低了。
對于這個問題,只存在于 TIMESTAMP 中,因為 DATETIME 不存在時區(qū)轉化問題。
對于 TIMESTAMP,建議使用顯式的時區(qū),而不是操作系統(tǒng)時區(qū)。
3. int
字符串費空間,TIMESTAMP 和 DATETIME 如果沒有吃透則總感覺亂亂的,所以也有人存時間戳,存一個 int 類型的數(shù)值,用一個時間戳來表示時間。
用 int 保存時間的話,當我們需要進行日期排序以及按照日期范圍查詢的時候,就變成了普通的數(shù)字比較了,那么效率肯定是杠杠滴。
不過 int 有一個致命的問題就是可讀性太差,所以用不用 int 就要仔細斟酌看情況了。
好啦,小伙伴們留言說說你日常開發(fā)日期用的哪種類型呢?出于什么樣的考慮用了該類型?