SQL 數(shù)據(jù)庫設(shè)計(jì)儲(chǔ)存表時(shí)日期時(shí)間字段類型 DATETIME 和 TIMESTAMP 的選擇
當(dāng)前位置:點(diǎn)晴教程→知識(shí)管理交流
→『 技術(shù)文檔交流 』
一、不要用字符串存儲(chǔ)日期 和許多數(shù)據(jù)庫初學(xué)者一樣,筆者在早期學(xué)習(xí)階段也曾嘗試使用字符串(如 VARCHAR)類型來存儲(chǔ)日期和時(shí)間,甚至一度認(rèn)為這是一種簡單直觀的方法。畢竟,'YYYY-MM-DD HH:MM:SS' 這樣的格式看起來清晰易懂。 但是,這是不正確的做法,主要會(huì)有下面兩個(gè)問題: 1、空間效率:與 MySQL 內(nèi)建的日期時(shí)間類型相比,字符串通常需要占用更多的存儲(chǔ)空間來表示相同的時(shí)間信息。 2、查詢與計(jì)算效率低下:
? 二、DATETIME 和 TIMESTAMP 選擇 DATETIME 和 TIMESTAMP 是 MySQL 中兩種非常常用的、用于存儲(chǔ)包含日期和時(shí)間信息的數(shù)據(jù)類型。它們都可以存儲(chǔ)精確到秒(MySQL 5.6.4+ 支持更高精度的小數(shù)秒)的時(shí)間值。那么,在實(shí)際應(yīng)用中,我們應(yīng)該如何在這兩者之間做出選擇呢? 下面我們從幾個(gè)關(guān)鍵維度對(duì)它們進(jìn)行對(duì)比: DATETIME 類型存儲(chǔ)的是字面量的日期和時(shí)間值,它本身不包含任何時(shí)區(qū)信息。當(dāng)你插入一個(gè) DATETIME 值時(shí),MySQL 存儲(chǔ)的就是你提供的那個(gè)確切的時(shí)間,不會(huì)進(jìn)行任何時(shí)區(qū)轉(zhuǎn)換。 這樣就會(huì)有什么問題呢? 如果你的應(yīng)用需要支持多個(gè)時(shí)區(qū),或者服務(wù)器、客戶端的時(shí)區(qū)可能發(fā)生變化,那么使用 DATETIME 時(shí),應(yīng)用程序需要自行處理時(shí)區(qū)的轉(zhuǎn)換和解釋。如果處理不當(dāng)(例如,假設(shè)所有存儲(chǔ)的時(shí)間都屬于同一個(gè)時(shí)區(qū),但實(shí)際環(huán)境變化了),可能會(huì)導(dǎo)致時(shí)間顯示或計(jì)算上的混亂。 TIMESTAMP 和時(shí)區(qū)有關(guān)。存儲(chǔ)時(shí),MySQL 會(huì)將當(dāng)前會(huì)話時(shí)區(qū)下的時(shí)間值轉(zhuǎn)換成 UTC(協(xié)調(diào)世界時(shí))進(jìn)行內(nèi)部存儲(chǔ)。當(dāng)查詢 TIMESTAMP 字段時(shí),MySQL 又會(huì)將存儲(chǔ)的 UTC 時(shí)間轉(zhuǎn)換回當(dāng)前會(huì)話所設(shè)置的時(shí)區(qū)來顯示。 這意味著,對(duì)于同一條記錄的 TIMESTAMP 字段,在不同的會(huì)話時(shí)區(qū)設(shè)置下查詢,可能會(huì)看到不同的本地時(shí)間表示,但它們都對(duì)應(yīng)著同一個(gè)絕對(duì)時(shí)間點(diǎn)(UTC 時(shí)間)。這對(duì)于需要全球化、多時(shí)區(qū)支持的應(yīng)用來說非常有用。 下面實(shí)際演示一下! 建表 SQL 語句:
插入一條數(shù)據(jù)(假設(shè)當(dāng)前會(huì)話時(shí)區(qū)為系統(tǒng)默認(rèn),例如 UTC+0):
查詢數(shù)據(jù)(在同一時(shí)區(qū)會(huì)話下):
結(jié)果:
現(xiàn)在,修改當(dāng)前會(huì)話的時(shí)區(qū)為東八區(qū) (UTC+8):
再次查詢數(shù)據(jù):
擴(kuò)展:MySQL 時(shí)區(qū)設(shè)置常用 SQL 命令
下圖是 MySQL 日期類型所占的存儲(chǔ)空間(官方文檔傳送門:https://dev.mysql.com/doc/refman/8.0/en/storage-requirements.html):
在 MySQL 5.6.4 之前,DateTime 和 TIMESTAMP 的存儲(chǔ)空間是固定的,分別為 8 字節(jié)和 4 字節(jié)。但是從 MySQL 5.6.4 開始,它們的存儲(chǔ)空間會(huì)根據(jù)毫秒精度的不同而變化,DateTime 的范圍是 5~8 字節(jié),TIMESTAMP 的范圍是 4~7 字節(jié)。 TIMESTAMP 表示的時(shí)間范圍更小,只能到 2038 年:
由于 TIMESTAMP 在存儲(chǔ)和檢索時(shí)需要進(jìn)行 UTC 與當(dāng)前會(huì)話時(shí)區(qū)的轉(zhuǎn)換,這個(gè)過程可能涉及到額外的計(jì)算開銷,尤其是在需要調(diào)用操作系統(tǒng)底層接口獲取或處理時(shí)區(qū)信息時(shí)。雖然現(xiàn)代數(shù)據(jù)庫和操作系統(tǒng)對(duì)此進(jìn)行了優(yōu)化,但在某些極端高并發(fā)或?qū)ρ舆t極其敏感的場景下,DATETIME 因其不涉及時(shí)區(qū)轉(zhuǎn)換,處理邏輯相對(duì)更簡單直接,可能會(huì)表現(xiàn)出微弱的性能優(yōu)勢。 為了獲得可預(yù)測的行為并可能減少 TIMESTAMP 的轉(zhuǎn)換開銷,推薦的做法是在應(yīng)用程序?qū)用娼y(tǒng)一管理時(shí)區(qū),或者在數(shù)據(jù)庫連接/會(huì)話級(jí)別顯式設(shè)置 time_zone 參數(shù),而不是依賴服務(wù)器的默認(rèn)或操作系統(tǒng)時(shí)區(qū)。 三、數(shù)值時(shí)間戳是更好的選擇嗎? 除了上述兩種類型,實(shí)踐中也常用整數(shù)類型(INT 或 BIGINT)來存儲(chǔ)所謂的“Unix 時(shí)間戳”(即從 1970 年 1 月 1 日 00:00:00 UTC 起至目標(biāo)時(shí)間的總秒數(shù),或毫秒數(shù))。 這種存儲(chǔ)方式的具有 TIMESTAMP 類型的所具有一些優(yōu)點(diǎn),并且使用它的進(jìn)行日期排序以及對(duì)比等操作的效率會(huì)更高,跨系統(tǒng)也很方便,畢竟只是存放的數(shù)值。缺點(diǎn)也很明顯,就是數(shù)據(jù)的可讀性太差了,你無法直觀的看到具體時(shí)間。 時(shí)間戳的定義如下: 時(shí)間戳的定義是從一個(gè)基準(zhǔn)時(shí)間開始算起,這個(gè)基準(zhǔn)時(shí)間是「1970-1-1 00:00:00 +0:00」,從這個(gè)時(shí)間開始,用整數(shù)表示,以秒計(jì)時(shí),隨著時(shí)間的流逝這個(gè)時(shí)間整數(shù)不斷增加。這樣一來,我只需要一個(gè)數(shù)值,就可以完美地表示時(shí)間了,而且這個(gè)數(shù)值是一個(gè)絕對(duì)數(shù)值,即無論的身處地球的任何角落,這個(gè)表示時(shí)間的時(shí)間戳,都是一樣的,生成的數(shù)值都是一樣的,并且沒有時(shí)區(qū)的概念,所以在系統(tǒng)的中時(shí)間的傳輸中,都不需要進(jìn)行額外的轉(zhuǎn)換了,只有在顯示給用戶的時(shí)候,才轉(zhuǎn)換為字符串格式的本地時(shí)間。 數(shù)據(jù)庫中實(shí)際操作:
四、PostgreSQL 中沒有 DATETIME 由于有讀者提到 PostgreSQL(PG) 的時(shí)間類型,因此這里拓展補(bǔ)充一下。PG 官方文檔對(duì)時(shí)間類型的描述地址:https://www.postgresql.org/docs/current/datatype-datetime.html。 PostgreSQL 時(shí)間類型總結(jié) 可以看到,PG 沒有名為 DATETIME 的類型:
對(duì)于絕大多數(shù)需要記錄精確發(fā)生時(shí)間點(diǎn)的應(yīng)用場景,TIMESTAMPTZ是 PostgreSQL 中最推薦、最健壯的選擇,因?yàn)樗茏詈玫靥幚頃r(shí)區(qū)復(fù)雜性。 五、總結(jié) MySQL 中時(shí)間到底怎么存儲(chǔ)才好?DATETIME?TIMESTAMP?還是數(shù)值時(shí)間戳? 并沒有一個(gè)銀彈,很多程序員會(huì)覺得數(shù)值型時(shí)間戳是真的好,效率又高還各種兼容,但是很多人又覺得它表現(xiàn)的不夠直觀。 《高性能 MySQL 》這本神書的作者就是推薦 TIMESTAMP,原因是數(shù)值表示時(shí)間不夠直觀。下面是原文:
每種方式都有各自的優(yōu)勢,根據(jù)實(shí)際場景選擇最合適的才是王道。下面再對(duì)這三種方式做一個(gè)簡單的對(duì)比,以供大家實(shí)際開發(fā)中選擇正確的存放時(shí)間的數(shù)據(jù)類型: 選擇建議小結(jié):
該文章在 2025/6/3 9:15:58 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |