恰當的數據類型選型是高性能 Schema 設計的基石。本文系統梳理 MySQL 8.0 主流數據類型的存儲特性、適用場景與避坑指南,並詳解 9 大常用字段屬性的實戰意義。
| 類型 | 存儲 | 範圍 | 精度 | 推薦場景 |
|---|---|---|---|---|
| DATE | 3 bytes | 1000-01-01 ~ 9999-12-31 | 天 | 生日、紀念日、無時區業務 |
| TIME | 3 bytes | -838:59:59 ~ 838:59:59 | 秒 | 每日定時任務、工時統計 |
| DATETIME | 8 bytes | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | 秒 | 通用業務時間,不受時區影響 |
| TIMESTAMP | 4 bytes | 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC | 秒 | 自動記錄創建/更新時間,受時區影響 |
| YEAR | 1 byte | 1901 ~ 2155 | 年 | 年份維度統計 |
最佳實踐:
• created_at 用 TIMESTAMP DEFAULT CURRENT_TIMESTAMP
• updated_at 用 TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
• 歷史/未來日期業務用 DATETIME 避免 2038 年問題
| 類型 | 存儲 | 有符號範圍 | 無符號範圍 |
|---|---|---|---|
| TINYINT | 1B | -128 ~ 127 | 0 ~ 255 |
| SMALLINT | 2B | -32,768 ~ 32,767 | 0 ~ 65,535 |
| MEDIUMINT | 3B | -8,388,608 ~ 8,388,607 | 0 ~ 16,777,215 |
| INT | 4B | -2,147,483,648 ~ 2,147,483,647 | 0 ~ 4,294,967,295 |
| BIGINT | 8B | -9.22E18 ~ 9.22E18 | 0 ~ 1.84E19 |
選型原則:
• 主鍵 ID 必用 BIGINT UNSIGNED
• 狀態/枚舉類用 TINYINT UNSIGNED
• 計數器預估 < 42億 用 INT UNSIGNED
• INT(11) 中的 11 僅為顯示寬度,不影響存儲範圍
| 類型 | 存儲 | 精度 | 適用場景 |
|---|---|---|---|
| FLOAT(M,D) | 4B | 單精度 ~7 位有效數字 | 科學計算、非精確業務 |
| DOUBLE(M,D) | 8B | 雙精度 ~15 位有效數字 | 高精度科學計算 |
| DECIMAL(M,D) | M/2+2 B | 精確定點數,最多 65 位數字 | 金額、價格、比率、任何財務數據 |
血淚教訓:FLOAT(5,3) 插入 123.45678 實際存 99.999 (溢出截斷)。財務字段嚴禁使用浮點類型。
| 類型 | 最大長度 | 存儲特點 | 適用場景 |
|---|---|---|---|
| CHAR(N) | 255 字符 | 定長,右側空格填充,讀取時去除尾部空格 | MD5、UUID、身份證、固定長度代碼 |
| VARCHAR(N) | 65,535 字符 (受行大小 65,535B 限制) | 變長,1-2B 存長度,實際佔用 L+1/2B | 通用變長文本:名稱、郵箱、地址 |
| TINYTEXT | 255 字符 | 不需指定長度,離頁存儲 | 極短文本 |
| TEXT | 64KB | 離頁存儲,不支持 DEFAULT | 文章內容、日志 |
| MEDIUMTEXT | 16MB | 同上 | 長文本 |
| LONGTEXT | 4GB | 同上 | 超長文本 |
OPTIMIZE TABLE。utf8mb4 下:
• CHAR(32) 固定佔 32×4=128B
• VARCHAR(255) 最大佔 255×4+2=1022B
• 行大小限制 65,535B 含所有列開銷
| 類型 | 成員上限 | 存儲 | 特點 |
|---|---|---|---|
| ENUM | 65,535 | 1-2B (smallint) | 單選,內部按定義順序存 1,2,3... NULL 索引為 NULL,空串索引 0 |
| SET | 64 | 1-8B (bigint 位掩碼) | 多選,位運算,尾部空格自動去除 |
慎用:修改成員需 ALTER TABLE 鎖表,不利擴展。推薦用 TINYINT + 應用層字典或查表。
-- 方案一:無符號 INT (4B) + MySQL 內建函數
INSERT INTO t(ip) VALUES (INET_ATON('192.168.1.1')); -- 3232235777
SELECT INET_NTOA(ip) FROM t; -- '192.168.1.1'
-- 方案二:VARBINARY(16) 支持 IPv6
INSERT INTO t(ip) VALUES (INET6_ATON('2001:db8::1'));
SELECT INET6_NTOA(ip) FROM t;
-- PHP 端轉換
sprintf("%u", ip2long('192.168.1.1')); -- 无符号整型
long2ip($int);
| 屬性 | 核心作用 | 關鍵限制/注意點 |
|---|---|---|
AUTO_INCREMENT | 自增主鍵,插入時自動分配唯一整數 | 必須為索引 (PK/UK);每表僅一列;ALTER TABLE t AUTO_INCREMENT=1000 設起始值 |
BINARY | CHAR/VARCHAR 大小寫敏感比較/排序 | 僅影響該列排序規則,不改變存儲 |
DEFAULT | 缺省值,INSERT 不指定列時自動填充 | 必須為常量/函數 (如 CURRENT_TIMESTAMP);BLOB/TEXT 不支持 |
INDEX / KEY | 創建普通索引,加速查詢 | 前綴索引 idx_name(name(10)) 節省空間;覆蓋索引避免回表 |
NOT NULL | 禁止 NULL,插入 NULL 報錯 | 配合 DEFAULT 確保數據完整性;COUNT(col) 不統計 NULL |
NULL | 允許 NULL (默認) | NULL ≠ 空串 ≠ 0;索引中 NULL 不計入唯一性約束 |
PRIMARY KEY | 主鍵:唯一 + 非空 + 聚簇索引 | 單表唯一;可多列組合;業務無關字段宜用自增 BIGINT |
UNIQUE | 唯一約束,允許多個 NULL | 本質是唯一索引;業務鍵 (手機、郵箱、身份證) 必加 |
ZEROFILL | 數值左側補 0 至顯示寬度,隱含 UNSIGNED | INT(5) ZEROFILL 插入 4 存為 00004;僅顯示效果,不改存儲 |
-- 僅 InnoDB 支持
ALTER TABLE `order`
ADD CONSTRAINT fk_order_user
FOREIGN KEY (user_id) REFERENCES `user`(id)
ON UPDATE CASCADE ON DELETE RESTRICT;
CASCADE:級聯更新/刪除SET NULL:置空 (需列允許 NULL)RESTRICT/NO ACTION:拒絕父表操作高併發系統常業務層維護引用完整性,避免外鍵鎖爭用與死鎖風險。
BIGINT UNSIGNED AUTO_INCREMENT PKNOT NULL DEFAULT 'xxx',業務無特殊含義禁用 NULLutf8mb4,校對 utf8mb4_unicode_ci 或 _0900_ai_ciInnoDBcreated_at, updated_at, deleted_at (軟刪除)tbl_ 前綴可選,索引 idx_/uk_合理的類型選型與屬性約束,能從源頭避免 80% 的數據質量與性能問題。