萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 資料庫 >> MySQL 教學

MySQL Schema 設計進階(二):資料型別精選與 timestamp 避坑指南

「不當家不知柴米貴」,Schema 設計中資料型別的選擇直接決定儲存成本、索引大小、CPU 計算效率。本文深入剖析 INT(M) 顯示寬度迷思、VARCHAR(N) 最大長度計算、TIMESTAMP vs DATETIME 選型陷阱。

一、INT(M):M 只是顯示寬度,不影響儲存

  • INT 永遠佔 4 位元組,有號範圍 -2147483648 ~ 2147483647。
  • M (1~255) 僅影響 ZEROFILL 時的前導零填充顯示。
CREATE TABLE t (id INT(2));
INSERT INTO t VALUES (10086);  -- 正常寫入,顯示 10086
ALTER TABLE t MODIFY id INT(16) ZEROFILL;
SELECT * FROM t;  -- 0000000000010086
ALTER TABLE t MODIFY id INT(5) ZEROFILL;
SELECT * FROM t;  -- 10086 (寬度不足不截斷)

結論: 忽略 M,直接寫 INT 或 BIGINT;需要前導零才加 ZEROFILL(隱含 UNSIGNED)。

二、VARCHAR(N) 最大 N 計算實戰

單行上限 65535 位元組(不含 BLOB/TEXT 溢位頁)。扣除開銷:

  • 長度前綴:1 位元組 (<255) 或 2 位元組 (>=255)。
  • NULL 位圖:每 8 欄位 1 位元組。
  • 字符集:latin1=1、gbk=2、utf8=3、utf8mb4=4 位元組/字元。

單表單欄位極限實測

-- latin1 (1 byte/char)
CREATE TABLE t (c VARCHAR(65533) CHARSET latin1);  -- OK (65533+1+1=65535)
CREATE TABLE t (c VARCHAR(65534) CHARSET latin1);  -- ERROR 1118 Row size too large

-- utf8 (3 bytes/char)
-- (65535 - 1 - 2) / 3 = 21844
CREATE TABLE t (c VARCHAR(21844) CHARSET utf8);  -- OK

面試題:CREATE TABLE t (col1 INT, col2 CHAR(50), col3 VARCHAR(N)) CHARSET=utf8; N 最大?

行開銷:col1 4B + col2 50×3=150B + col3 長度前綴 2B + NULL 位圖 1B = 157B 已用。
剩餘:65535 - 157 = 65378 B → N = FLOOR(65378 / 3) = 21792。

三、TIMESTAMP 那些事

為何首選 TIMESTAMP?

  • 儲存 4 位元組 (DATETIME 8 位元組,DATE 8 位元組)。
  • 自帶時區轉換:寫入時轉 UTC,讀出轉回 Session 時區,跨時區應用零成本。
  • DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP 內建建立/更新時間戳。

DATETIME 直接相減的坑

CREATE TABLE t (start DATETIME, stop DATETIME);
INSERT INTO t VALUES ('2014-01-19 21:46:18', '2014-01-20 00:21:31');
SELECT stop - start FROM t;  -- 787513 (數字相減,非時間差!)

正確做法:TIMESTAMPDIFF(SECOND, start, stop) 或 UNIX_TIMESTAMP(stop) - UNIX_TIMESTAMP(start)。

版本差異與 SHOW CREATE TABLE 驗證

MySQL 5.6 前:TIMESTAMP 預設 NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(首欄自動加)。
5.6.6+:explicit_defaults_for_timestamp=ON 關閉隱式預設值。
最佳實踐: 顯式指定所有屬性,建表後用 SHOW CREATE TABLE 確認實際 DDL。

避免 INT UNSIGNED 存 Unix 時間戳

雖同為 4 位元組,但失去 FROM_UNIXTIME()/UNIX_TIMESTAMP() 函數支援、時區自動轉換、DATE_FORMAT 直讀等便利,維護成本更高。

型別選型決策樹

  1. 整數:TINYINT/SMALLINT/MEDIUMINT/INT/BIGINT → 依最大值選最小型別,UNSIGNED 翻倍正數範圍。
  2. 定長字串 (≤ 20 字元且長度固定):CHAR(如 MD5、UUID、ISO 代碼)。
  3. 變長字串:VARCHAR(N),N 為業務實際上限,編碼 utf8mb4。
  4. 日期時間:TIMESTAMP (1970-2038) 或 DATETIME (1000-9999),需跨世紀用後者。
  5. 精確小數:DECIMAL(p,s)(金額、比率),禁止 FLOAT/DOUBLE。
  6. 大文本/二進位:TEXT/BLOB 族,必要時外部儲存 (S3/MinIO) + 存 URL。

嚴選型別、拒絕冗餘,是 Schema 設計的最高原則。

copyright © 萬盛學電腦網 all rights reserved