主鍵生成策略爭論由來已久。核心原則:**主鍵應為「非業務主鍵」**,即無業務含義、不可變、單純作為行識別碼。在此前提下:
自增整數 (BIGINT AUTO_INCREMENT)
| 優點 | 缺點 |
| 空間小 (8 字節)、索引緊湊、範圍查詢極快 | 分庫分表需額外協調 (雪花算法/段號)、插入熱點導致頁爭用、洩露業務量級 |
| 人類可讀、除錯方便、支援 `LAST_INSERT_ID()` | 合併資料、異地多活極難、安全性稍弱 (可猜測遞增) |
UUID (CHAR(36) / BINARY(16) / UUID v7)
| 優點 | 缺點 |
| 全域唯一、無協調、天然支援分庫分表/多主寫入 | 佔用空間大 (36/16 字節)、索引分裂嚴重、範圍查詢慢 |
| 不洩露業務資訊、安全性高 | 人類難讀、除錯需轉換、InnoDB 主鍵聚簇索引導致寫入擴散 |
決策矩陣
- 單體應用、單表 < 5000 萬、無分表計畫 → **自增 BIGINT** 最划算。
- 微服務、分庫分表、多寫入節點、異地多活 → **UUID (建議 v7 有序 UUID)** 或 **雪花算法 (64-bit Long)**。
- 既要有序又要分散 → **UUID v7 (時間戳前綴 + 隨機)** 或 **TSID**;若用 MySQL 8.0+ 可直接 `UUID_TO_BIN(UUID(), TRUE)` 存 `BINARY(16)` 並啟用 `innodb_optimize_fulltext_only=OFF` 減少分裂。
避坑指南
- **嚴禁用業務欄位作主鍵** (身分證、手機、訂單號) —— 會導致更新級聯、分表路由失靈。
- **UUID 存 CHAR(36) 且未轉 BINARY** → 索引體積膨脹 2 倍、比較慢,務必用 `BINARY(16)` + `UUID_TO_BIN/BIN_TO_UUID`。
- **自增 ID 用完** → `BIGINT` 上限 922京,單表極難用盡;若真用盡,改用 `UNSIGNED BIGINT` 或遷移 UUID。
圖片對比表已整理:
結論:沒有銀彈,只有場景適配。 先定架構演進路線,再選主鍵策略。