主鍵與索引是關系數據庫的兩大基石,但常被混淆。本文從定義、物理存儲、約束特性、查詢加速機制四個維度,深度剖析主鍵(邏輯鍵)與索引(物理鍵)的聯系與區別,並釐清「主鍵一定是索引,索引不一定是主鍵」的核心邏輯。
| 維度 | 主鍵 | 索引 |
|---|---|---|
| 本質 | 邏輯概念:業務層面的唯一標識符 | 物理結構:B+Tree/Hash 等數據結構文件 |
| 核心職責 | 1. 唯一標識行 2. 被外鍵引用(參照完整性) | 加速數據檢索(WHERE/JOIN/ORDER BY/GROUP BY) |
| 強制性 | 表應當有主鍵(InnoDB 強制生成隱式行 ID) | 可選,按查詢需求創建 |
| 數量限制 | 每表僅一個 | 每表可建多個(單表建議 ≤ 5) |
InnoDB 採用索引組織表(IOT)架構:
MyISAM:非聚簇,主鍵/二級索引葉子節點均存行指針(文件偏移量),數據文件與索引文件分離。
| 特性 | 主鍵 | 唯一索引 | 普通索引 |
|---|---|---|---|
| 唯一性 | 強制 | 強制 | 不強制 |
| 允許 NULL | 不允許(任何列) | 允許(多個 NULL 視為不相等) | 允許 |
| 自動創建索引 | 是(聚簇索引) | 是(二級唯一索引) | 手動創建 |
| 可被外鍵引用 | 是 | 是(MySQL 允許引用唯一索引) | 否 |
| 修改成本 | 極高(涉及行移動、二級索引主鍵值更新) | 中(修改索引樹) | 中 |
WHERE id > 100 → 聚簇索引範圍掃描,順序讀取葉子頁。WHERE status = 1 → 二級索引定位葉子節點 → 回表取行。SELECT id, status FROM t WHERE status = 1 → 二級索引 (status, id) 直接返回,零回表。ORDER BY status / GROUP BY status → 索引天然有序,避免 filesort/臨時表。(a,b,c) 支持 a/a,b/a,b,c 前綴匹配。| 誤區 | 真相 | 最佳實踐 |
|---|---|---|
| 「主鍵就是索引,別再建索引了」 | 主鍵只能加速主鍵列查詢,業務查詢列需單獨建二級索引 | 按 WHERE/JOIN/ORDER BY 列建立二級索引,利用覆蓋索引 |
| 「唯一索引不能有 NULL」 | MySQL 唯一索引允許多個 NULL(NULL != NULL) | 業務要求強制非空請加 NOT NULL 約束 |
| 「外鍵必須引用主鍵」 | MySQL 允許外鍵引用唯一索引列 | 大表核心業務不建物理外鍵,應用層維護完整性 |
| 「聯表查詢只需在 JOIN 列建索引」 | 驅動表的過濾列、排序列同樣關鍵 | 全鏈路分析:驅動表過濾索引 + 被驅動表 JOIN 索引 + 覆蓋索引 |
| 「索引越多越好」 | 每個索引增加寫入開銷、佔用空間、優化器選擇成本 | 單表 ≤ 5 個索引,定期 sys.schema_unused_indexes 清理 |
BIGINT AUTO_INCREMENT,單調遞增,頁分裂最少,二級索引存儲主鍵值最小(8 字節)。row_id(不可見、不可用),極不推薦。主鍵是邏輯鍵,索引是物理鍵。主鍵通過聚簇索引決定數據物理存儲順序,二級索引通過主鍵值回表定位行。
核心認知:
1. 主鍵約束 ≠ 索引功能:主鍵保證唯一非空、被引用;索引加速查詢。
2. InnoDB 主鍵即數據:主鍵設計直接決定存儲效率與查詢性能。
3. 索引服務於查詢模式:慢查詢驅動索引創建,定期清理無用索引。
掌握這層關系,是從「會用數據庫」到「懂數據庫」的關鍵跨越。