「直接把所有欄位定成 VARCHAR(255) 不就好了?」——這是許多初學者的直覺,但會帶來儲存浪費、查詢效能低落、排序錯誤、索引無法建立等連鎖問題。欄位型別選擇是資料庫設計的基石,影響儲存空間、I/O 效率、CPU 計算成本、索引可用性、排序語意、應用程式資料對應。本文建立一套從「資料特性分析」到「效能權衡決策」的系統化選型框架,協助您做出最適合業務場景的型別決策。
| 維度 | 關鍵問題 | 決策導向 |
|---|---|---|
| 資料本質 | 儲存的是數值、文字、日期、二進位、列舉值? | 數值用數值型、日期用日期型、固定集合用 ENUM/SET |
| 取值範圍 | 最小/最大值?是否含負數?精度需求? | 剛好覆蓋範圍的最小型別;整數優先 UNSIGNED |
| 效能考量 | 查詢頻率、索引需求、排序方式、連線比對? | 定長>變長、數值>字串、短型別>長型別、可索引型別優先 |
| 比較語意 | 大小寫敏感?自訂排序順序? | BINARY/字元集決定比較規則;ENUM 可自訂排序 |
| 索引相容 | 需建立索引?MySQL 版本限制? | 早期版本 BLOB/TEXT 不可索引、索引欄需 NOT NULL |
| 型別 | 位元組 | 有號範圍 | 無號範圍 | 適用場景 |
|---|---|---|---|---|
| TINYINT | 1 | -128~127 | 0~255 | 布林旗標、極小計數、狀態碼 |
| SMALLINT | 2 | -32K~32K | 0~65K | 中小計數、年齡、郵遞區號 |
| MEDIUMINT | 3 | -8M~8M | 0~16M | 中等流水號、中型表主鍵 |
| INT | 4 | -21億~21億 | 0~42億 | 通用主鍵、大計數、Unix 時間戳 |
| BIGINT | 8 | -9E18~9E18 | 0~1.8E19 | 極大流水號、分散式 ID、位元組計數 |
黃金法則:UNSIGNED 除非必須存負數;AUTO_INCREMENT 欄位必加 UNSIGNED;不確定範圍時寧大勿小(ALTER TABLE 可擴大,縮小需確保資料不溢位)。
| 型別 | 儲存方式 | 精度 | 適用場景 |
|---|---|---|---|
| DECIMAL(M,D) | 字串逐位儲存 | 精確至 D 位小數 | 金額、匯率、精確計算(避免捨入誤差) |
| FLOAT | 4 位元組 IEEE 754 | ~7 位有效數字 | 科學計算、座標、非關鍵近似值 |
| DOUBLE | 8 位元組 IEEE 754 | ~15 位有效數字 | 高精度科學計算 |
金額處理最佳實踐:DECIMAL(12,2) 儲存分為單位的整數(如 12345 代表 123.45),或 BIGINT 儲存最小貨幣單位(分/分),應用層負責格式化顯示。
| 型別 | 最大長度 | 儲存開銷 | 適用場景 |
|---|---|---|---|
| CHAR(N) | 255 | N 位元組(右補空格) | 固定長度代碼(ISO 國家碼、MD5 雜湊、身分證字號) |
| VARCHAR(N) | 65,535 | 實際長度+1~2 位元組 | 變長文字(姓名、地址、標題、URL) |
| TINYTEXT | 255 | 長度+1 | 極短備註、標籤 |
| TEXT | 64KB | 長度+2 | 文章內容、JSON 文檔、日誌 |
| MEDIUMTEXT | 16MB | 長度+3 | 長文檔、原始碼 |
| LONGTEXT | 4GB | 長度+4 | 極大文本、完整書刊 |
關鍵權衡:
CHAR 定長優勢:無碎片、固定位移快速定位、ORDER BY 效能佳VARCHAR 節省空間,但頻繁 UPDATE 易產生碎片,需定期 OPTIMIZE TABLEVARCHAR/TEXTBINARY/VARBINARY 對應位元組語意,比較區分大小寫、無字元集轉換| 型別 | 範圍 | 儲存 | 含時區 | 適用場景 |
|---|---|---|---|---|
| DATE | 1000-01-01 ~ 9999-12-31 | 3 位元組 | 否 | 生日、發票日期、無時間需求 |
| TIME | -838:59:59 ~ 838:59:59 | 3 位元組 | 否 | 持續時間、每日固定時段 |
| DATETIME | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | 8 位元組 | 否 | 歷史記錄、固定時區應用 |
| TIMESTAMP | 1970-01-01 ~ 2038-01-19 | 4 位元組 | 是(儲存 UTC,顯示轉換) | 建立/更新時間戳、跨時區應用 |
| YEAR | 1901 ~ 2155 | 1 位元組 | 否 | 年份統計、車款年份 |
決策關鍵:
TIMESTAMP(注意 2038 年問題)DATETIMEDATE + TIME(允許 NULL 表示無時間)0 月/日,或拆分 YEAR/MONTH/DAY 欄位| 特性 | ENUM | SET |
|---|---|---|
| 本質 | 單選:從預定列表選一值 | 多選:從預定列表選零或多值 |
| 內部儲存 | 數值索引(1~65535) | 位元組合(最多 64 個成員) |
| 效能 | 數值比較極快、體積極小 | 位元運算快速、體積小 |
| 排序 | 依定義順序排序(非字母順) | 依位元值排序 |
| 適用場景 | 狀態機(pending/approved/rejected)、性別、分類 | 標籤系統、權限位遮罩、多選屬性 |
限制:成員列表修改需 ALTER TABLE,大量成員時 DDL 鎖表久;避免用於頻繁變動的分類體系。
CHAR、INT、DATESMALLINT 足夠時勿用 INT;VARCHAR(40) 足夠時勿用 VARCHAR(255)ENUM 獲數值運算優勢SELECT * FROM tbl PROCEDURE ANALYSE(10,2000) 獲取型別建議MD5())、避免 SELECT * 拖回大欄位VARCHAR/BLOB 的高頻寫入表CREATE TABLE t (
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
...
);
四大必要條件:整數型別 + 索引(PK/UNIQUE)+ NOT NULL(舊版強制)+ UNSIGNED(建議)。
| 反模式 | 問題 | 修正 |
|---|---|---|
| 手機號用 BIGINT | 前導零消失、無法存 +86、非數學運算欄位 | VARCHAR(20) 或 CHAR(11) |
| 金額用 FLOAT | 捨入誤差導致對帳失敗 | DECIMAL(12,2) 或 BIGINT(分) |
| 所有字串 VARCHAR(255) | 索引長度限制(767 bytes)、排序緩衝區浪費 | 依實際最大長度定義 |
| 狀態碼用 VARCHAR | 比較慢、易輸入錯誤、無排序語意 | ENUM 或 TINYINT + 應用層常數映射 |
| 時間戳用 DATETIME 但跨時區 | 夏令時/時區切換資料錯亂 | TIMESTAMP 或應用層統一 UTC |
欄位型別選擇沒有標準答案,只有「在特定業務約束下的最優解」。建立資料剖析 → 範圍量化 → 效能權衡 → 索引規劃 → 未來擴充評估的標準化決策流程,並善用 PROCEDURE ANALYSE()、EXPLAIN、壓力測試驗證選型,才能打造既節省資源又高效能的資料庫結構。記住:型別是契約,不只是容器——它定義了資料的語意邊界與操作規則。