下图展示了聚簇索引中的记录是如何存放的。
![](http://dl2.iteye.com/upload/attachment/0128/0623/e8c02c09-43fd-36df-9a93-20699c3f2193.png)
InnoDB 引擎是通过主键来聚集数据的,这表示图中“被索引的列”就是主键列。如果没有定义主键,InnoDB 会选择一个唯一的非空索引代替。如果没有这样的索引,它会隐式定义一个主键来作为聚簇索引。InnoDB 只聚集在同一个页面中的记录,因此包含相邻键值的页面可能会相距甚远。
聚集的数据主要有以下这些重要的优点:
(1)可以把相关数据保存在一起。例如实现电子邮箱时,可以根据用户 ID 来聚集数据,这样就只需要从磁盘读取少数的数据页就能获取某个用户的全部邮件。如果没有使用聚簇索引,则每封邮件都可能导致一次磁盘 I/O。
(2)数据访问更快。聚簇索引将索引和数据保存在同一个 B-Tree 中,因此从聚簇索引中获取数据通常比在非聚簇索引中查找要快。
(3)使用覆盖索引扫描的查询可以直接使用页节点中的主键值。
而聚簇索引也有一些缺点:
(1)聚簇数据最大限度地提高了 I/O 密集型应用的性能,但如果数据全部都存放在内存中,则访问的顺序就没那么重要了,聚簇索引也就没什么优势了。
(2)插入速度严重依赖于插入顺序。按照主键的顺序插入是加载数据到 InnoDB 表中速度最快的方式,但如果不是按照主键顺序加载数据,那么在加载完成后最好使用 OPTIMIZE TABLE 命令重新组织一下表。
(3)更新聚簇索引列的代价很高,因为会强制 InnoDB 将每个被更新的行移动到新的位置。
(4)基于聚簇索引的表在插入新行或者主键被更新导致需要移动行的时候,可能面临“页分裂”的问题。当行的主键值要求必须将这一行插入到某个已满的页中时,存储引擎会将该页分成两个页面来容纳该行。页分裂会导致表占用更多的磁盘空间。
(5)聚簇索引可能导致全表扫描变慢,尤其是行比较稀疏,或者由于页分裂导致数据存储不连续的时候。
(6)二级索引(非聚簇索引)可能比想象的要更大,因为在二级索引的叶子节点包含了引用行的主键列。
(7)二级索引访问需要两次索引查找,而不是一次。因为二级索引叶子节点保存的不是指向行的物理位置的指针,而是行的主键值。这表示通过二级索引查找行时,存储引擎需要找到二级索引的叶子节点获得对应的主键值,然后根据这个值去聚簇索引中找到对应的行。不过对于 InnoDB,自适应哈希索引能够减少这样的重复工作。