沈老師,我聽網上說,MySQL資料表,在資料量比較大的情況下,主鍵不宜過長,是不是這樣呢?這又是為什麼呢? 這個問題嘛,不能一概而論:(1)如果是InnoDB存儲引擎,主鍵不宜過長;(2)如果是MyISAM存儲引擎,影響不大; 先舉個簡單的栗子說明一下前序知識。 假設有資料表:
t(id PK, name KEY, sex, flag);
其中:(1)id是主鍵;(2)name建了普通索引; 假設表中有四條記錄:
1, shenjian, m, A
3, zhangsan, m, A
5, lisi, m, A
9, wangwu, f, B
如果存儲引擎是MyISAM,其索引與記錄的結構是這樣的:

(1)有單獨的區域存儲記錄
(record);(2)主鍵索引與普通索引結構相同,都存儲記錄的指針(暫且了解為指針);畫外音:(1)主鍵索引與記錄不存儲在一起,是以它是非聚集索引(Unclustered Index);(2)MyISAM可以沒有PK; MyISAM使用索引進行檢索時,會先從索引樹定位到記錄指針,再通過記錄指針定位到具體的記錄。畫外音:不管主鍵索引,還普通索引,過程相同。 InnoDB則不同,其索引與記錄的結構是這樣的:
(1)主鍵索引與記錄存儲在一起;
(2)普通索引存儲主鍵(這下不是指針了);畫外音:(1)主鍵索引與記錄存儲在一起,是以才叫聚集索引(Clustered Index);(2)InnoDB一定會有聚集索引; InnoDB通過主鍵索引查詢時,能夠直接定位到行記錄。
但如果通過
普通索引查詢時,會先查詢出主鍵,再從主鍵索引上二次周遊索引樹。 回歸正題,為什麼InnoDB的主鍵不宜過長呢? 假設有一個使用者中心場景,包含身份證号,身份證MD5,姓名,出生年月等業務屬性,這些屬性上均有查詢需求。
最容易想到的設計方式是:
- 身份證作為主鍵
- 其他屬性上建立索引
user(id_code PK,
id_md5(index),
name(index),
birthday(index));
此時的索引樹與行記錄結構如上:
- id_code聚集索引,關聯行記錄
- 其他索引,存儲id_code屬性值
身份證号id_code是一個比較長的字元串,每個索引都存儲這個值,在資料量大,記憶體珍貴的情況下,MySQL有限的緩沖區,存儲的索引與資料會減少,磁盤IO的機率會增加。畫外音:同時,索引占用的磁盤空間也會增加。 此時,應該新增一個無業務含義的id自增列:
- 以id自增列為聚集索引,關聯行記錄
- 其他索引,存儲id值
user(id PK auto inc,
id_code(index),
如此一來,有限的緩沖區,能夠緩沖更多的索引與行資料,磁盤IO的頻率會降低,整體性能會增加。 總結(1)MyISAM的索引與資料分開存儲,索引葉子存儲指針,主鍵索引與普通索引無太大差別;(2)InnoDB的聚集索引和資料行統一存儲,聚集索引存儲資料行本身,普通索引存儲主鍵;(3)InnoDB不建議使用太長字段作為PK(此時可以加入一個自增鍵PK),MyISAM則無所謂;
本文轉自“架構師之路”公衆号,58沈劍提供。