來源:
《高性能mysql(第三版)》
假如有以下表:
create table test (
col1 int not null,
col2 int not null,
primary key(col1),
key(col2)
);
假設該表的主鍵值取值1-10000,按照隨機順序插入並使用OPTIMIZE TABLE 命令做了優化。也就是說,數據在磁盤上的存儲方式已經最優,但是行的順序是隨機的,列col2的值1-100之間的隨機值,所以有很多重複的值。
我們先介紹MyISAM的數據分佈:
MyISAM按照數據插入的順序存儲在磁盤上,如下表:
行號 | col1 | col2 |
---|---|---|
0 | 99 | 8 |
1 | 12 | 56 |
2 | 3000 | 62 |
….
行號 | col1 | col2 |
---|---|---|
9997 | 18 | 8 |
9998 | 4700 | 13 |
9999 | 3 | 93 |
因為這裡行是定長的,所以MyISAM可以從表的開始跳過所需的字節找到需要的行。(對於變長的行使用不同的策略,這裡暫不介紹)
這種分佈方式很容易創建索引,下圖顯示了表的主鍵分佈:

可以看到,葉子節點按照主鍵排序好了,而且還保存了行號。
那麼MyISAM下,col2上的索引有什麼不同呢?答案是完全一樣的存儲方式,只是把主鍵列換成col2列罷了。這裡就不再贅述。
再來看InnoDB的數據分佈:
下面是InnoDB的主鍵分佈:

注意看,上圖顯示了整個表,而不是隻有索引。
因為在InnoDB中,聚簇索引 “就是”表。所以不像MyISAM那樣需要獨立的行儲存。
每個葉子節點都包含了主鍵值,事務id, 回滾指針(用於事務和mvvc),以及所有剩餘的列(這個例子是col2)
除此以外,InnoDB的二級索引和聚簇索引很不同,和MyISAM的索引也不一樣。如下圖:

InnoDB的二級索引的葉子節點存儲的不是行號,而是主鍵值。這樣的策略減少了當出現行移動或者數據頁分裂時二級索引的維護工作。使用主鍵值當工作指針會讓二級索引佔用更多的空間,換來的好處是,InnoDB在移動行時不必更新二級索引的這個“指針”。
上圖我們省略了非葉子節點的細節,它包含了索引列和一個指向下一個節點的指針。
總結
- MyISAM的主鍵索引和二級索引存儲方式一樣,都是存放的索引列和行號。索引文件和數據文件分開的。
- InnoDB的主鍵索引包含了主鍵和其他全部列,以及其他信息(主鍵索引和數據文件是一起的);二級索引則是一個單獨的文件,存放索引列和主鍵值。