<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
今天我們來探討一個有意思的問題,先說場景:
那如何實現查詢兩個快照之間的【變更記錄】有哪些呢?
快照 和 變更記錄 預期是兩張表。首先我們不能將【變更記錄】通過 id 掛在某個【快照】上,因為我們的快照是不斷被回收的,這樣的話當你回收快照時,也需要連帶著更新大量的【變更記錄】,出現寫擴散。
另一個想法是,能否通過時間戳進行比較?比如快照 A 的建立時間戳是 12345,快照 B 的建立時間戳是 23456。那麼我只要【變更記錄】這張表也有一個時間戳欄位,寫一個 SQL 查到兩個快照時間戳之間的變更記錄是不是就可以了?
寫出來 SQL 類似這樣:
select * from change_record where create_time > 12345 and create_time < 23456;
那麼,問題來了,這個 create_time,雖然這裡我們直接拿時間戳比較,但真的是效能最好的麼?建表的時候,我應該用 datetime, timestamp 還是 int ?
今天我們就來看看到底有什麼區別。
任何一篇部落格,教學都比不上官方檔案,大家選型有疑慮時還是建議先來看看 MySQL Data Types 。
我們先來看 integer 有什麼型別。
SQL 標準中對於整數,提出了兩種型別:INTEGER(INT) 以及 SMALLINT。在此之外,MySQL 還額外提供了 TINYINT, MEDIUMINT, BIGINT 三種型別。
所以一共是五種:
可以看到,INT 其實和我們通常用的 int32 是一樣的,本質是 2 的 31 次方 - 1,大概21億4千7百萬。(正整數以二進位制儲存。負整數以二補數儲存。一個Int型別資料佔據空間4位元組。每個位元組8位元,共32位元。因此最大儲存2的31次方(從2的0次方開始)。但32位元的第一位是符號位。所以2的31次方減1.簡單說Int型別佔據4位元組,所以是這個取值範圍。)
這裡 BIGINT 就等價於 int64。
datetime 其實是一個統稱,MySQL 提供了 DATE, DATETIME, TIMESTAMP 三種型別。
The
DATE
type is used for values with a date part but no time part. MySQL retrieves and displaysDATE
values in'YYYY-MM-DD'
format. The supported range is'1000-01-01'
to'9999-12-31'
.
DATE 型別沒有具體的時間點,只能精確到【日期】,即 YYYY-MM-DD,比如 1994-06-09。
The
DATETIME
type is used for values that contain both date and time parts. MySQL retrieves and displaysDATETIME
values in'YYYY-MM-DD hh:mm:ss'
format. The supported range is'1000-01-01 00:00:00'
to'9999-12-31 23:59:59'
.
DATETIME 則同時支援【日期】和【時間】,格式為 YYYY-MM-DD hh:mm:ss。如 1995-04-29 17:11:12。
The
TIMESTAMP
data type is used for values that contain both date and time parts.TIMESTAMP
has a range of'1970-01-01 00:00:01'
UTC to'2038-01-19 03:14:07'
UTC.
TIMESTAMP 同樣也支援【日期】和【時間】,但由於帶上了時間戳的語意,就不如 DATETIME 支援的範圍那麼寬了。UTC 時間,從'1970-01-01 00:00:01' UTC 到 '2038-01-19 03:14:07'
因為此前的系統設計都是基於 32 位實現的,我們上面提到過,最多無非是 2 的 31次方 - 1,每個數代表一秒的話,最多表示 68 年。所以 Unix 選取了 1970年1月1日作為UNIX TIME的紀元時間(開始時間)。
這裡我們主要還是關心 DATETIME 以及 TIMESTAMP,二者除了整秒之外,還可以支援小數點後的部分,最多到 microseconds (6位)精度。格式為 'YYYY-MM-DD hh:mm:ss
[.fraction
]',比如 '2038-01-19 03:14:07.999999' (事實上這也是 TIMESTAMP 能支援的最大值)。
除此之外,二者也都支援 自動初始化(Automatic Initialization)。這裡要用到的兩個大殺器:
DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
二者可以同時出現,也可以單獨出現,分幾種情況:
CREATE TABLE t1 ( ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );
此時 ts 和 dt 的預設值就是當前時間,當這一行其他值發生變化時,也會自動把這兩個屬性更新為當前時間。
CREATE TABLE t1 ( ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP, dt DATETIME DEFAULT CURRENT_TIMESTAMP );
此時只有初始化的時候才會寫入當前時間,隨後更新時不會變動。(當然,我們也可以把 CURRENT_TIMESTAMP 換成一個常數,比如 0,語法上是支援的,只不過那樣就不是當前時間了)
CREATE TABLE t1 ( ts1 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, -- default 0 ts2 TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP -- default NULL );
此時沒有指定預設值,但發生更新時會改為當前時間,這時的預設值就是 type dependent,依賴型別了。 TIMESTAMP 的預設值為 0,如果定義了 NULL 則預設值為 NULL。
CREATE TABLE t1 ( dt1 DATETIME ON UPDATE CURRENT_TIMESTAMP, -- default NULL dt2 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP -- default 0 );
這次我們換成了 DATETIME,二者正好相反,不指定 DEFAULT 的話,預設值為 NULL,但如果我們宣告了 NOT NULL,則預設值變成 0。
show variables like '%explicit_defaults_for_timestamp%';
來檢視是否禁用了自動初始化和更新。MySQL converts
TIMESTAMP
values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such asDATETIME
.)
TIMESTAMP 底層採用 4 個位元組儲存(2的31次方-1,還記得麼),能支援的時間範圍比 DATETIME 要小一倍,但它的特點在於,當我們寫入時,MySQL會根據當前 server 所在的時區進行轉換,將值變成 UTC 時區的時間,再儲存。同樣的,在查詢的時候,MySQL 也會幫助我們轉成當前時區再展示。這是 DATETIME 不具備的。
這樣的跨時區支援,在一些業務場景下是很有用的。畢竟儲存時間這件事情本身是很敏感的。海外使用者一開始請求到了新加坡機房,落了一個時間。隨後跑到歐洲玩耍,在法國重新存取,發現跟本地時間完全對不上,這就有問題了。
所以 TIMESTAMP 的思路就是,大家都以 UTC 時間為準,這是個基線,不管你是哪個時區的,我都要轉成統一的時間,查詢的時候給你轉回去就是了。
我們可以用 show variables like '%time_zone%';
來檢視當前庫的時區:
需要注意,當MySQL引數time_zone=system時,查詢timestamp欄位會呼叫系統時區做時區轉換,而由於系統時區存在全域性鎖問題,在多並行巨量資料量存取時會導致執行緒上下文頻繁切換,CPU使用率暴漲,系統響應變慢設定假死。
The time zone can be set on a per-connection basis, as described in MySQL Server Time Zone Support.
使用 SET TIME_ZONE = 'america/new_york";
來設定時區。每個連線可以使用不同的時區
可以實驗一下,在一個時區寫入 TIMESTAMP 資料,切換時區後讀出來,顯示的時間是不一樣的,而 DATETIME 則是完全一致的。demo
DATETIME 底層採用 8 個位元組儲存,沒有跨時區的支援,結果直接展示。你存進去的是什麼時間,讀到的就是什麼時間。不過我們如果需要跨時區,也不是沒有辦法,可以在讀出來 DATETIME 後轉為時間戳,從業務程式碼層面來處理,想轉成什麼時區都 OK。
這裡不用擔心 2038 年的限制,雖然空間大了一倍,但通常情況下不會造成多大效能影響。
這裡在討論完 DATETIME, TIMESTAMP 之後,我們回過頭來看看 Integer。
為什麼我們能用一個整數來代表時間呢?這裡本質是我們給它賦予了【時間戳】的語意。
雖然整數的上下限更大(比如我們用 BIGINT,可以支援 2 的 63 次方 - 1 的資料),但是,但是,用法是關鍵。
如果你打算還用時間戳函數進行生成和轉換,那就需要關注 2038 年這個限制,本質上和 TIMESTAMP 是沒有區別的。
所以,通常我們認為,用整型時間戳的形式,取值範圍也是 1970 年 1 月 1日起,到 2038 年截止,這個區間。用 BIGINT 的意義不大,只要它的語意還是時間戳,就需要遵循這個規範。
回到我們一開始提到的案例,我們需要篩選出兩個時間點之間,有哪些【變更記錄】。
如果是整型,我們其實經常使用 BETWEEN 來進行查詢:
SELECT * FROM contacts WHERE contact_id BETWEEN 100 AND 200;
它和下面直接用運運算元的形式是等價的,注意 BETWEEN 是個閉區間:
SELECT * FROM contacts WHERE contact_id >= 100 AND contact_id <= 200;
同樣的,查詢 datetime 依然可以用 BETWEEN:
SELECT * FROM `objects` WHERE (date_field BETWEEN '2010-01-30 14:15:55' AND '2010-09-29 10:15:55')
下面兩個查詢也是等價的:
SELECT count(*) FROM `table` where created_at>='2011-03-17 06:42:10' and created_at<='2011-03-17 07:42:50';
SELECT count(*) FROM `table` where created_at between '2011-03-17 06:42:10' and '2011-03-17 07:42:50';
當然,我們也可以用 now()
等函數作為輔助,注意 between 裡面一定要先寫小的時間,and 後面寫更大的時間點。
The DATETIME type is used when you need values that contain both date and time information. MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD HH:MM:SS' format. The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.
The TIMESTAMP data type has a range of '1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' UTC. It has varying properties, depending on the MySQL version and the SQL mode the server is running in.
其實 DATETIME 和 TIMESTAMP 底層也是整型儲存(否則就不會按照 2 的31 次方,63 次方來支援了),算是一層封裝,提供了一系列時間函數使用。
DATETIME 底層儲存實現是 BigInt,索引儲存上和 BigInt 的處理是幾乎一模一樣的,所以 BigInt 支援的索引查詢,datetime也支援。
加上索引後的速度如何,推薦大家閱讀這一篇 benchmark MYSQL 資料庫時間欄位 INT,TIMESTAMP,DATETIME 效能效率的比較介紹
這裡參照一下結論:
大家可以嘗試一下,結合你的業務場景,跑一下 explain 看看。
到此這篇關於MySQL 時間型別用 datetime, timestamp 還是 integer 更好的文章就介紹到這了,更多相關MySQL 時間型別使用內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45