1. 程式人生 > >MySQL 中你應該使用什麼資料型別表示時間?

MySQL 中你應該使用什麼資料型別表示時間?

導讀 當你需要儲存日期時間資料時,一個問題來了:你應該使用 MySQL 中的什麼型別?使用 MySQL 原生的 DATE 型別還是使用 INT 欄位把日期和時間儲存為一個純數字呢?

在這篇文章中,我將解釋 MySQL 原生的方案,並給出一個最常用資料型別的對比表。我們也將對一些典型的查詢做基準測試,然後得出在給定場景下應該使用什麼資料型別的結論。
如果你想直接看結論,請翻到文章最下方。

原生的 MySQL Datetime 資料型別

Datetime 資料表示一個時間點。這可以用作日誌記錄、物聯網時間戳、日曆事件資料,等等。MySQL 有兩種原生的型別可以將這種資訊儲存在單個欄位中:Datetime 和 Timestamp。MySQL 文件中是這麼介紹這些資料型別的:

DATETIME 型別用於儲存同時包含日期和時間兩部分的值。MySQL 以 'YYYY-MM-DD HH:MM:SS' 形式接收和顯示 DATETIME 型別的值。
TIMESTAMP 型別用於儲存同時包含日期和時間兩部分的值。
DATETIME 或 TIMESTAMP 型別的值可以在尾部包含一個毫秒部分,精確度最高到微秒(6 位數)。
TIMESTAMP 和 DATETIME 資料型別提供自動初始化和更新到當前的日期和時間的功能,只需在列的定義中設定 DEFAULT CURRENTTIMESTAMP 和 ON UPDATE CURRENTTIMESTAMP。

作為一個例子:

CREATE TABLE `datetime_example` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `measured_on` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `measured_on` (`measured_on`)
) ENGINE=InnoDB;
CREATE TABLE `timestamp_example` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `measured_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `measured_on` (`measured_on`)
) ENGINE=InnoDB;

除了原生的日期時間表示方法,還有另一種常用的儲存日期和時間資訊的方法。即使用 INT 欄位儲存 Unix 時間(從1970 年 1 月 1 日協調世界時(UTC)建立所經過的秒數)。
MySQL 也提供了只儲存時間資訊中的一部分的方式,通過使用 Date、Year 或 Time 型別。由於這篇文章是關於儲存準確時間點的最佳方式的,我們沒有討論這些不那麼精確的區域性型別。

使用 INT 型別儲存 Unix 時間

使用一個簡單的 INT 列儲存 Unix 時間是最普通的方法。使用 INT,你可以確保你要儲存的數字可以快速、可靠地插入到表中,就像這樣:

INSERT INTO `vertabelo`.`sampletable`
(
 `id`,
 `measured_on` ### INT 型別的列
)
VALUES
(
 1,
 946684801
 ### 至 01/01/2000 @ 12:00am (UTC) 的 UNIX 時間戳 http://unixtimestamp.com
);

這就是關於它的所有內容了。它僅僅是個簡單的 INT 列,MySQL 的處理方式是這樣的:在內部使用 4 個位元組儲存那些資料。所以如果你在這個列上使用 SELECT 你將會得到一個數字。如果你想把這個列用作日期進行比較,下面的查詢並不能正確工作:

SELECT
    id, measured_on, FROM_UNIXTIME(measured_on)
FROM
    vertabelo.inttimestampmeasures
WHERE
    measured_on > '2016-01-01' ### measured_on 會被作為字串比較以進行查詢
LIMIT 5;

這是因為 MySQL 把 INT 視為數字,而非日期。為了進行日期比較,你必須要麼獲取( LCTT 譯註:從 1970-01-01 00:00:00)到 2016-01-01 經過的秒數,要麼使用 MySQL 的 FROM_UNIXTIME() 函式把 INT 列轉為 Date 型別。下面的查詢展示了 FROM_UNIXTIME() 函式的用法:

SELECT
    id, measured_on, FROM_UNIXTIME(measured_on)
FROM
    vertabelo.inttimestampmeasures
WHERE
    FROM_UNIXTIME(measured_on) > '2016-01-01'
LIMIT 5;

這會正確地獲取到日期在 2016-01-01 之後的記錄。你也可以直接比較數字和 2016-01-01 的 Unix 時間戳表示形式,即 1451606400。這樣做意味著不用使用任何特殊的函式,因為你是在直接比較數字。查詢如下:

SELECT
    id, measured_on, FROM_UNIXTIME(measured_on)
FROM
    vertabelo.inttimestampmeasures
WHERE
   measured_on > 1451606400
LIMIT 5;

假如這種方式不夠高效甚至提前做這種轉換是不可行的話,那該怎麼辦?例如,你想獲取 2016 年所有星期三的記錄。要做到這樣而不使用任何 MySQL 日期函式,你就不得不查出 2016 年每個星期三的開始和結束時間的 Unix 時間戳。然後你不得不寫很大的查詢,至少要在 WHERE 中包含 104 個比較。(2016 年有 52 個星期三,你不得不考慮一天的開始(0:00 am)和結束(11:59:59 pm)...)
結果是你很可能最終會使用 FROM_UNIXTIME() 轉換函式。既然如此,為什麼不試下真正的日期型別呢?

使用 Datetime 和 Timestamp

Datetime 和 Timestamp 幾乎以同樣的方式工作。兩種都儲存日期和時間資訊,毫秒部分最高精確度都是 6 位數。同時,使用人類可讀的日期形式如 "2016-01-01" (為了便於比較)都能工作。查詢時兩種型別都支援“寬鬆格式”。寬鬆的語法允許任何標點符號作為分隔符。例如,"YYYY-MM-DD HH:MM:SS" 和 "YY-MM-DD HH:MM:SS" 兩種形式都可以。在寬鬆格式情況下以下任何一種形式都能工作:

2012-12-31 11:30:45
2012^12^31 11+30+45
2012/12/31 11*30*45
[email protected]@31 11^30^45

其它寬鬆格式也是允許的;你可以在 MySQL 參考手冊 找到所有的格式。
預設情況下,Datetime 和 Timestamp 兩種型別查詢結果都以標準輸出格式顯示 —— 年-月-日 時:分:秒 (如 2016-01-01 23:59:59)。如果使用了毫秒部分,它們應該以小數值出現在秒後面 (如 2016-01-01 23:59:59.5)。
Timestamp 和 Datetime 的核心不同點主要在於 MySQL 在內部如何表示這些資訊:兩種都以二進位制而非字串形式儲存,但在表示日期/時間部分時 Timestamp (4 位元組) 比 Datetime (5 位元組) 少使用 1 位元組。當儲存毫秒部分時兩種都使用額外的空間 (1-3 位元組)。如果你儲存 150 萬條記錄,這種 1 位元組的差異是微不足道的:

150 萬條記錄 * 每條記錄 1 位元組 / (1048576 位元組/MB) = 1.43 MB

Timestamp 節省的 1 位元組是有代價的:你只能儲存從 '1970-01-01 00:00:01.000000' 到 '2038-01-19 03:14:07.999999' 之間的時間。而 Datetime 允許你儲存從 '1000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999' 之間的任何時間。
另一個重要的差別 —— 很多 MySQL 開發者沒意識到的 —— 是 MySQL 使用伺服器的時區轉換 Timestamp 值到它的 UTC 等價值再儲存。當獲取值是它會再次進行時區轉換,所以你得回了你“原始的”日期/時間值。有可能,下面這些情況會發生。
理想情況下,如果你一直使用同一個時區,MySQL 會獲取到和你儲存的同樣的值。以我的經驗,如果你的資料庫涉及時區變換,你可能會遇到問題。例如,伺服器變化(比如,你把資料庫從都柏林的一臺伺服器遷移到加利福尼亞的一臺伺服器上,或者你只是修改了一下伺服器的時區)時可能會發生這種情況。不管哪種方式,如果你獲取資料時的時區是不同的,資料就會受影響。
Datetime 列不會被資料庫改變。無論時區怎樣配置,每次都會儲存和獲取到同樣的值。就我而言,我認為這是一個更可靠的選擇。

MySQL 文件:
MySQL 把 TIMESTAMP 值從當前的時區轉換到 UTC 再儲存,獲取時再從 UTC 轉回當前的時區。(其它型別如 DATETIME 不會這樣,它們會“原樣”儲存。) 預設情況下,每個連線的當前時區都是伺服器的時區。時區可以基於連線設定。只要時區設定保持一致,你就能得到和儲存的相同的值。如果你儲存了一個 TIMESTAMP 值,然後改變了時區再獲取這個值,獲取到的值和你儲存的是不同的。這是因為在寫入和查詢的會話上沒有使用同一個時區。當前時區可以通過系統變數 time_zone 的值得到。更多資訊,請檢視 MySQL Server Time Zone Support。

對比總結

在深入探討使用各資料型別的效能差異之前,讓我們先看一個總結表格以給你更多瞭解。每種型別的弱點以紅色顯示。

特性 Datetime Timestamp Int (儲存 Unix 時間)
原生時間表示 否,所以大多數操作需要先使用轉換函式,如 FROM_UNIXTIME()
能儲存毫秒 是,最高 6 位精度 是,最高 6 位精度
合法範圍 '1000-01-01 00:00:00.000000' 到 '9999-12-31 23:59:59.999999 '1970-01-01 00:00:01.000000' 到 '2038-01-19 03:14:07.999999' 若使用 unsigned, '1970-01-01 00:00:01.000000; 理論上最大到 '2106-2-07 06:28:15'
自動初始化(MySQL 5.6.5+)
否,必須使用正確的格式
值被轉換到 UTC 儲存
可轉換到其它型別 是,如果值在合法的 Timestamp 範圍中 是,總是 是,如果值在合法的範圍中並使用轉換函式
儲存需求(MySQL 5.6.4+) 5 位元組(如果使用了毫秒部分,再加最多 3 位元組) 4 位元組 (如果使用了毫秒部分,再加最多 3 位元組) 4 位元組 (不允許毫秒部分)
無需使用函式即可作為真實日期可讀 否,你必須格式化輸出
資料分割槽 是,使用 UNIX_TIMESTAMP();在 MySQL 5.7 中其它表示式是不允許包含 TIMESTAMP 值的。同時,注意分割槽裁剪時的這些考慮 是,使用 INT 上的任何合法操作
基準測試 INT、Timestamp 和 Datetime 的效能

為了比較這些型別的效能,我會使用我建立的一個天氣預報網路的 150 萬記錄(準確說是 1,497,421)。這個網路每分鐘都收集資料。為了讓這些測試可復現,我已經刪除了一些私有列,所以你可以使用這些資料執行你自己的測試。
基於我原始的表格,我建立了三個版本:

 datetimemeasures表在 measured_on 列使用 Datetime 型別,表示天氣預報記錄的測量時間
 timestampmeasures表在 measured_on 列使用 Timestamp 型別
 inttimestampmeasures表在 measured_on 列使用 INT (unsigned) 型別

這三個表擁有完全相同的資料;唯一的差別就是 measured_on 欄位的型別。所有表都在 measured_on 列上設定了一個索引。

基準測試工具

為了評估這些資料型別的效能,我使用了兩種方法。一種基於 Sysbench,它的官網是這麼描述的:

... 一個模組化、跨平臺和多執行緒的基準測試工具,用以評估那些對執行高負載資料庫的系統非常重要的系統引數。

這個工具是 MySQL 文件中推薦的。

如果你使用 Windows (就像我),你可以下載一個包含可執行檔案和我使用的測試查詢的 zip 檔案。它們基於 一種推薦的基準測試方法。

為了執行一個給定的測試,你可以使用下面的命令(插入你自己的連線引數):

sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=sysbench_test_file.lua --num-threads=8 --max-requests=100 run

這會正常工作,這裡 sysbench_test_file.lua 是測試檔案,幷包含了各個測試中指向各個表的 SQL 查詢。

為了進一步驗證結果,我也運行了 mysqlslap。它的官網是這麼描述的:

“mysqlslap 是一個診斷程式,為模擬 MySQL 伺服器的客戶端負載並報告各個階段的用時而設計。它工作起來就像是很多客戶端在同時訪問伺服器。”

記得這些測試中最重要的不是所需的絕對時間。而是在不同資料型別上執行相同查詢時的相對時間。這兩個基準測試工具的測試時間不一定相同,因為不同工具的工作方式不同。重要的是資料型別的比較,隨著我們深入到測試中,這將會變得清楚。

基準測試

我將使用三種可以評估幾個效能方面的查詢:

  • 時間範圍選擇
    • 在 Datetime 和 Timestamp 資料型別上這允許我們直接比較而不需要使用任何特殊的日期函式。
    • 同時,我們可以評估在 INT 型別的列上使用日期函式相對於使用簡單的數值比較的影響。為了做到這些我們需要把範圍轉換為 Unix 時間戳數值。
  • 日期函式選擇
    • 與前個測試中比較操作針對一個簡單的 DATE 值相反,這個測試使得我們可以評估使用日期函式作為 “WHERE” 子句的一部分的效能。
    • 我們還可以測試一個場景,即我們必須使用一個函式將 INT 列轉換為一個合法的 DATE 型別然後執行查詢。
  • count() 查詢
    • 作為對前面測試的補充,這將評估在三種不同的表示型別上進行典型的統計查詢的效能。

我們將在這些測試中覆蓋一些常見的場景,並看到三種類型上的效能表現。

關於 SQL_NO_CACHE

當在查詢中使用 SQL_NO_CACHE 時,伺服器不使用查詢快取。它既不檢查查詢快取以確認結果是不是已經在那兒了,也不會儲存查詢結果。因此,每個查詢將反映真實的效能影響,就像每次查詢都是第一次被呼叫。

測試 1:選擇一個日期範圍中的值

這個查詢返回總計 1,497,421 行記錄中的 75,706 行。
查詢 1 和 Datetime:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.datetimemeasures m
WHERE
    m.measured_on > '2016-01-01 00:00:00.0'
      AND m.measured_on < '2016-02-01 00:00:00.0';

效能

響應時間 (ms) Sysbench mysqlslap
最小 152 296
最大 1261 3203
平均 362 809
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=datetime.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.datetimemeasures m WHERE m.measured_on > '2016-01-01 00:00:00.0' AND m.measured_on < '2016-02-01 00:00:00.0'" --host=localhost --user=root --concurrency=8 --iterations=100  --no-drop --create-schema=vertabelo

查詢 1 和 Timestamp:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.timestampmeasures m
WHERE
    m.measured_on > '2016-01-01 00:00:00.0'
        AND m.measured_on < '2016-02-01 00:00:00.0';

效能

響應時間 (ms) Sysbench mysqlslap
最小 214 359
最大 1389 3313
平均 431 1004
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=timestamp.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.timestampmeasures m WHERE m.measured_on > '2016-01-01 00:00:00.0' AND m.measured_on < '2016-02-01 00:00:00.0'" --host=localhost --user=root --concurrency=8 --iterations=100  --no-drop --create-schema=vertabelo

查詢 1 和 INT:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.inttimestampmeasures m
WHERE
    FROM_UNIXTIME(m.measured_on) > '2016-01-01 00:00:00.0'
        AND FROM_UNIXTIME(m.measured_on) < '2016-02-01 00:00:00.0';

效能

響應時間 (ms) Sysbench mysqlslap
最小 2472 7968
最大 6554 10312
平均 4107 8527
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=int.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.inttimestampmeasures m WHERE FROM_UNIXTIME(m.measured_on) > '2016-01-01 00:00:00.0' AND FROM_UNIXTIME(m.measured_on) < '2016-02-01 00:00:00.0'" --host=localhost --user=root --concurrency=8 --iterations=100  --no-drop --create-schema=vertabelo

另一種 INT 上的查詢 1:
由於這是個相當直接的範圍搜尋,而且查詢中的日期可以輕易地轉為簡單的數值比較,我將它包含在了這個測試中。結果證明這是最快的方法 (你大概已經預料到了),因為它僅僅是比較數字而沒有使用任何日期轉換函式:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.inttimestampmeasures m
WHERE
    m.measured_on > 1451617200
        AND m.measured_on < 1454295600;

效能

響應時間 (ms) Sysbench mysqlslap
最小 88 171
最大 275 2157
平均 165 514
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=basic_int.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.inttimestampmeasures m WHERE m.measured_on > 1451617200 AND m.measured_on < 1454295600" --host=localhost --user=root --concurrency=8 --iterations=100  --no-drop --create-schema=vertabelo

測試 1 總結

平均響應時間 (ms) Sysbench 相對於 Datetime 的速度 mysqlslap 相對於 Datetime 的速度
Datetime 362 - 809 -
Timestamp 431 慢 19% 1004 慢 24%
INT 4107 慢 1134% 8527 慢 1054%
另一種 INT 查詢 165 快 55% 514 快 36%

兩種基準測試工具都顯示 Datetime 比 Timestamp 和 INT 更快。但 Datetime 沒有我們在另一種 INT 查詢中使用的簡單數值比較快。

測試 2:選擇星期一產生的記錄

這個查詢返回總計 1,497,421 行記錄中的 221,850 行。
查詢 2 和 Datetime:

SELECT SQL_NO_CACHE measured_on
FROM
    vertabelo.datetimemeasures m
WHERE
    WEEKDAY(m.measured_on) = 0; # MONDAY

效能

響應時間 (ms) Sysbench mysqlslap
最小 1874 4343
最大 6168 7797
平均 3127 6103
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=datetime_1.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.datetimemeasures m WHERE WEEKDAY(m.measured_on) = 0" --host=localhost --user=root --concurrency=8 --iterations=25 --no-drop --create-schema=vertabelo

查詢 2 和 Timestamp:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.timestampmeasures m
WHERE
    WEEKDAY(m.measured_on) = 0; # MONDAY

效能

響應時間 (ms) Sysbench mysqlslap
最小 2688 5953
最大 6666 13531
平均 3653 8412
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=timestamp_1.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.timestampmeasures m WHERE WEEKDAY(m.measured_on) = 0" --host=localhost --user=root --concurrency=8 --iterations=25 --no-drop --create-schema=vertabelo

查詢 2 和 INT:

SELECT SQL_NO_CACHE
    measured_on
FROM
    vertabelo.inttimestampmeasures m
WHERE
    WEEKDAY(FROM_UNIXTIME(m.measured_on)) = 0; # MONDAY

效能

響應時間 (ms) Sysbench mysqlslap
最小 2051 5844
最大 7007 10469
平均 3486 8088
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=int_1.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE measured_on FROM vertabelo.inttimestampmeasures m WHERE WEEKDAY(FROM_UNIXTIME(m.measured_on)) = 0" --host=localhost --user=root --concurrency=8 --iterations=25  --no-drop --create-schema=vertabelo

測試 2 總結

平均響應時間 (ms) Sysbench 相對於 Datetime 的速度 mysqlslap 相對於 Datetime 的速度
Datetime 3127 - 6103 -
Timestamp 3653 慢 17% 8412 慢 38%
INT 3486 慢 11% 8088 慢 32%

再次,在兩個基準測試工具中 Datetime 比 Timestamp 和 INT 快。但在這個測試中,INT 查詢 —— 即使它使用了一個函式以轉換日期 —— 比 Timestamp 查詢更快得到結果。

測試 3:選擇星期一產生的記錄總數

這個查詢返回一行,包含產生於星期一的所有記錄的總數(從總共 1,497,421 行可用記錄中)。
查詢 3 和 Datetime:

SELECT SQL_NO_CACHE
    COUNT(measured_on)
FROM
    vertabelo.datetimemeasures m
WHERE
    WEEKDAY(m.measured_on) = 0; # MONDAY

效能

響應時間 (ms) Sysbench mysqlslap
最小 1720 4063
最大 4594 7812
平均 2797 5540
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=datetime_1_count.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE COUNT(measured_on) FROM vertabelo.datetimemeasures m WHERE WEEKDAY(m.measured_on) = 0" --host=localhost --user=root --concurrency=8 --iterations=25 --no-drop --create-schema=vertabelo

查詢 3 和 Timestamp:

SELECT SQL_NO_CACHE
    COUNT(measured_on)
FROM
    vertabelo.timestampmeasures m
WHERE
    WEEKDAY(m.measured_on) = 0; # MONDAY

效能

響應時間 (ms) Sysbench mysqlslap
最小 1907 4578
最大 5437 10235
平均 3408 7102
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=timestamp_1_count.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE COUNT(measured_on) FROM vertabelo.timestampmeasures m WHERE WEEKDAY(m.measured_on) = 0" --host=localhost --user=root --concurrency=8 --iterations=25 --no-drop --create-schema=vertabelo

查詢 3 和 INT:

SELECT SQL_NO_CACHE
    COUNT(measured_on)
FROM
    vertabelo.inttimestampmeasures m
WHERE
    WEEKDAY(FROM_UNIXTIME(m.measured_on)) = 0; # MONDAY

效能

響應時間 (ms) Sysbench mysqlslap
最小 2108 5609
最大 4764 9735
平均 3307 7416
Sysbench cmd> sysbench --MySQL-table-engine=innodb --MySQL-db=vertabelo --MySQL-user=root --MySQL-host=localhost --MySQL-password= --test=int_1_count.lua --num-threads=8 --max-requests=100 run
mysqlslap cmd> mysqlslap --query="SELECT SQL_NO_CACHE COUNT(measured_on) FROM vertabelo.inttimestampmeasures m WHERE WEEKDAY(FROM_UNIXTIME(m.measured_on)) = 0" --host=localhost --user=root --concurrency=8 --iterations=25  --no-drop --create-schema=vertabelo

測試 3 總結

平均響應時間 (ms) Sysbench 相對於 Datetime 的速度 mysqlslap 相對於 Datetime 的速度
Datetime 2797 - 5540 -
Timestamp 3408 慢 22% 7102 慢 28%
INT 3307 慢 18% 7416 慢 33%

再一次,兩個基準測試工具都顯示 Datetime 比 Timestamp 和 INT 快。不能判斷 INT 是否比 Timestamp 快,因為 mysqlslap 顯示 INT 比 Timestamp 略快而 Sysbench 卻相反。

注意: 所有測試都是在一臺 Windows 10 機器上本地執行的,這臺機器擁有一個雙核 i7 CPU,16GB 記憶體,執行 MariaDB v10.1.9,使用 innoDB 引擎。

結論

基於這些資料,我確信 Datetime 是大多數場景下的最佳選擇。原因是:

更快(根據我們的三個基準測試)。
無需任何轉換即是人類可讀的。
不會因為時區變換產生問題。
只比它的對手們多用 1 位元組
支援更大的日期範圍(從 1000 年到 9999 年)

如果你只是儲存 Unix 時間戳(並且在它的合法日期範圍內),而且你真的不打算在它上面使用任何基於日期的查詢,我覺得使用 INT 是可以的。我們已經看到,它執行簡單數值比較查詢時非常快,因為只是在處理簡單的數字。
Timestamp 怎麼樣呢?如果 Datetime 相對於 Timestamp 的優勢不適用於你特殊的場景,你最好使用時間戳。閱讀這篇文章後,你對三種類型間的區別應該有了更好的理解,可以根據你的需要做出最佳的選擇。

本文由 LCTT 原創編譯,Linux中國 榮譽推出

本文地址:http://www.linuxprobe.com/mysql-time.html
免費提供最新Linux技術教程書籍,為開源技術愛好者努力做得更多更好,開源站點:http://www.linuxprobe.com/

相關推薦

MySQL 應該使用什麼資料型別表示時間

導讀 當你需要儲存日期時間資料時,一個問題來了:你應該使用 MySQL 中的什麼型別?使用 MySQL 原生的 DATE 型別還是使用 INT 欄位把日期和時間儲存為一個純數字呢? 在這篇文章中,我將解釋 MySQL 原生的方案,並給出一個最常用資料型別的對比表。我們也

MySQL——5.MySQL支援的資料型別簡介

1.資料都儲存在資料庫中的資料表中。 2.這節課學習資料表的相關操作。 3.資料庫就好比一個excel表 。一個sheet就相當於一個數據庫,excel就相當於一個管理軟體。在sheet中新增一個表格,就相當於在資料庫中建立一個數據表

mysql 的tinyint 資料型別

mysql資料庫中以的型別是以 “ 資料型別(m) ” 來定義的 : 其中 數字m在不同的資料型別中表示含義是不同的。  整型數系統已經限制了取值範圍,比如tinyint佔一個位元組(8bit)、int佔4個位元組。 所以整型數後面的m不是表示的資料長度,而是表示資料

MYSQL支援的資料型別及取值範圍

DATE、TIME 和 TEAR 型別  MySQL用 DATE 和 TEAR 型別儲存簡單的日期值,使用 TIME 型別儲存時間值。這些型別可以描述為字串或不帶分隔符的整數序列。如果描述為字串,DATE 型別的值應該使用連字號作為分隔符分開,而 TIME 型別的值應該使用冒號作為分隔符分開。   需要注意的

MySQL資料型別 -- 日期時間

在MySQL關係型資料庫中,MySQL支援的資料型別非常豐富。它主要分為3大類,即:數值型,日期時間性,字元型。而實際上這三類資料型別可以進一步的細分擴充套件,可以根據業務需要選擇最適合的一種。本文主要介紹日期時間型別,並演示其用法。 一、日期時間型 MySQL

【小家SQL】MySql資料型別---日期時間型別的使用(含datetime和timestamp的區別)

每篇一句 練武不練功,到老一場空。 程式設計師應該注重內功的修煉,那才是核心競爭力 說在前面 在這一路學習過來,每次不管看書還是網上看的資料,對於MySQL資料型別中的時間日期型別總是一掃而過,不曾停下來認認真真的研究學習。最近看了一本關於MySql的書

mysqlTinyint(1)資料格式自動轉為boolean型別

一次專案中資料庫使用Tinyint(1),實體類使用boolean,剛開始還好奇怎麼可以這樣儲存, 不過自己測試了一下,set屬性為true,資料庫欄位自動儲存為1,set屬性為false,資料庫欄位自動儲存為0 後來網上查了相關資料,整理如下: 1.資料 1.MYSQL資

time_t資料型別表示的最遲時間

一、基本系統資料型別-time_t 在unix/linux系統中,時間的表示方法是以1970年1月1日00:00:00所經過的秒數,使用基本系統資料型別time_t表示,在/usr/include下查詢time_t型別的定義. 1. sys/types.h #defi

Java程式設計,什麼資料型別適合用來表示價格?

我在看書時候偶然看到這個問題,我的第一反應:這還用問嘛!!!float和double都可以呀。(這充分說明了我是java初學者。。。)不過,好學的我,還是想看看答案到底寫了個啥。答案如下:在初學Java的時候,我們知道float和double都表示浮點數。但是由於float和

JAVA的jdbc向MySql插入各種資料型別

pStmt=conn.prepareStatement("INSERT INTO RH_ENTRY"+ "(id,allow_comments,category_id,comment_count,content,create_on,name,status)"+ "values(?,?,?,?,?,?,?,?)

可能不知道的MySQL的定點數型別

定點數型別 正因為用浮點數表示小數可能會有不精確的情況,在一些情況下我們必須保證小數是精確的,所以設計MySQL的大叔們提出一種稱

MySQL的簡單資料查詢

查詢: 一:查詢所有資料 select * from Info 查所有資料 select Code,Name from Info 查特定列 二:根據條件查 select * from Info where Code='p001' 一個條件查詢 select * from Info where Cod

MySql啟用InnoDB資料引擎的方法

1、儲存引擎是什麼?   Mysql中的資料用各種不同的技術儲存在檔案(或者記憶體)中。這些技術中的每一種技術都使用不同的儲存機制、索引技巧、鎖定水平並且最終提供廣泛的不同的功能和能力。通過選擇不同的技術,你能夠獲得額外的速度或者功能,從而改善你的應用的整體功能。這些不同的技術以及配套的相關功能

JAVAString轉換資料型別原來這麼簡單

String型別的資料轉為byte陣列: String str=""qwertyuiop; byte [] bytes=str.getBytes(); byte位元組型別轉為String型別資料: String str=""qwertyuiop; byte [] byte

MySQL修改預設Blob資料型別大小(解決上傳1M以上檔案失敗的問題)

如果需要在MySQL中儲存二進位制資料,那麼肯定會用到 BLOB 型別的欄位。MySQL中,BLOB是個型別系列,包括:TinyBlob、Blob、MediumBlob、LongBlob,這幾個型別之間的唯一區別是在儲存檔案的最大大小的不同。 MySQL的四種 BLOB 型別: (單位:位元

java的基本資料型別轉換

1.java中的基本資料型別轉換 java基本資料型別的轉換是需要兩個基本事項: 1.boolean型不進行型別轉換。 2.Java中基本資料型別按精度從“低”到“高”排列順序     byte  short  char  int&

一些基本資料型別

8.13長物件 常物件的定義,使用關鍵字const。語法形式為:類名 const 物件名; 8.14常成員 類包括成員資料和成員函式,因此可以定義相應的常成員函式和常成員資料。 8.14.1常成員資料 其語法形式:   Const 資料型別 

Mysql效能優化之資料型別優化

一、選擇正確的資料型別對於獲得高效能至關重要 1.1更小的通常更好 佔用更少的磁碟、記憶體和CPU快取 1.2儘量避免null 如果查詢中包含可為null的列,對Mysql來說更難優化,因為可為null的列使得索引、索引統計和值都更復雜。會使用更多的儲存空間. 2、整數和實數

Java的八大資料型別詳談

JAVA中的八大資料型別 Java的基本資料型別在任何作業系統上都具有相同的大小 1.int 取值範圍-231~231-1 型別長度:4個位元組(32位) 預設值:0 2.short 取值範圍 -215~215-1 型別長度:2個位元組(16位) 3.long 型別長度:8個位元組(

Java的基本資料型別型別轉換規則(自動、強制)、原反補碼、使用者自定義識別符號

基本資料型別 資料型別指明瞭變數和表示式的狀態和行為。 基本資料型別 關鍵字 記憶體中佔用位元組數 取值範圍 布林型 boolean 1位元組(8bit)