核心差異
| 特性 | CHAR | VARCHAR |
| 儲存方式 | 定長,不足補空格 | 變長,實際長度+1-2 字節長度前綴 |
| 空間效率 | 固定佔用定義長度 | 僅佔用實際資料長度 |
| 讀取速度 | 固定偏移快 | 需解析長度前綴 |
| 碎片風險 | 無(定長) | 頻繁更新長度變化產生碎片 |
為何仍需 CHAR?
- 向下相容:早期資料庫僅支援 CHAR
- 內存對齊:部分引擎固定長度利於 CPU 快取行對齊(效能增益極微)
- 避免碎片:極高頻更新且長度變化大的場景(但 VARCHAR 節省空間通常更划算)
VARCHAR 長度定義的隱性影響
1. 業務約束
長度即資料驗證,STATUS VARCHAR(5) 僅允許 'NEW'/'DEL'/'CLOSE',防止髒資料入庫。
2. 儲存開銷差異
- MySQL:
<255 用 1 字節長度前綴,≥255 用 2 字節。VARCHAR(10) vs VARCHAR(256) 每行差 1 字節
- Oracle:動態編碼長度標識,無此問題
3. 索引限制
| 引擎 | 單欄上限 | 組合索引上限 |
| InnoDB | 767 字節(innodb_large_prefix 開啟 3072) | 3072 字節 |
| MyISAM | 1000 字節 | 1000 字節 |
| MEMORY | 3072 字節 | 3072 字節 |
Oracle:索引鍵長度 ≤ 區塊大小 75%(8K 區塊約 6398 字節),線上重建索引更嚴格(40% ≈ 3215)。超長 VARCHAR 無法建索引或線上重建,影響可用性。
4. 客戶端記憶體
JDBC/ODBC 驅動依定義長度分配緩衝區。VARCHAR(1000) 實際存 10 字元,讀 1 萬行 → 客戶端佔 10MB 有效資料卻分配 1GB 記憶體,高併發易 OOM。
5. 4/8 字節對齊迷思
實測無明顯效能增益,JDBC 驅動已將字串統一存大型 char[],對齊意義不大。
選型建議決策樹
- 長度完全可預估(年月、狀態、代碼) →
CHAR(n) 或 VARCHAR(實際長度)
- 長度可預估上限(姓名、標題) →
VARCHAR(合理上限),如 20/30/50
- 描述、備註、長文本、無索引需求 →
VARCHAR(1024) 或 TEXT
- 需建索引 → 嚴格控制長度在引擎上限內,預留線上重建空間
- 高併發/大量讀取 → 避免過大定義長度浪費客戶端記憶體
現代最佳實踐
- 預設選
VARCHAR,除非有明確 CHAR 優勢場景
- 使用
utf8mb4 字符集,字元長度 ≠ 字節長度(中文 3-4 字節)
- InnoDB 啟用
innodb_large_prefix 允許 3072 字節索引
- 定期
OPTIMIZE TABLE 整理碎片
- 上一篇文章: MySQL 獲取 ENUM 欄位所有可能值的快速方法
- 下一篇文章: Ubuntu 13.04 安裝與配置 MySQL 完整教學
Copyright ©
程式碼之家 All Rights Reserved