您的位置:首页 > 数据库 > MySQL

聚簇索引详解(转)

2014-11-28 18:17 429 查看
聚簇索引不是一个独立的索引类型,而是一种数据存储的方式。InnoDB使用B-Tree来实现聚簇索引,并把索引和数据存放在同一结构中。在有聚簇索引的表中,索引和行是存放在同一个叶子节点(B-Tree)中的。"聚簇"表示索引值相邻的行的存储位置一般也是相邻的——一般来说是这样,但在某些情况下不是。一张表只能有一个聚簇索引,因为同一份数据不可能出现两个地方。


图中展示了一个聚簇索引的示例,需要注意的是:只有叶子节点才包括了数据行的值,非叶子节点只存了索引字段。在某些DB实现中,可以选择按照哪个索引做聚簇,但是MySQL的所有存储都不支持这样——InnoDB只能按照主键做聚簇。如果表中没有定义主键,InnoDB会选择一个“非空且有唯一性约束“的索引来做聚簇,如果没有这样的索引,则会定义一个不可见的主键,并以这个主键来聚簇。

从图中的布局还可以看到,整个索引以B-Tree方式组织,其中叶子节点包含了行的主键值和这一行所有字段的值,非叶子节点只是单纯的提供查找路径信息。在非主键索引中,叶子节点存放的是索引字段的值和一个指向聚簇索引的”行指针“——对应行的主键的值。

InnoDB clusters records together only within a page.Pages with adjacent key values may be distant from each other.InnoDB的聚簇是页面级别的,即聚簇索引值相邻的行会被存入同一个页面,当这个页面存满时,接下来的相邻行会被存入另外一个页面,而这两个页面可能会离的很远。如图中的布局所示,索引值为1~10的行被存在第一个页面,11~20的行被存在另外一个页面,数据被聚簇在单个页面内,而页面1和页面2的磁盘位置却可能离的很远。

聚簇的好处:1. You can keep related data close together——在设计一个邮件系统时,按照(用户id,邮件id)来做聚簇,同一个用户的邮件会被存在相邻的磁盘区域,这样获取用户所有邮件的时候,磁盘IO开销就很小。2. Data access is fast——聚簇索引把索引和数据放在同一个B树中,在以聚簇索引获取整行数据会很快。3. Queries that use covering indexes can use the primary key values contained at the leaf node——只要是以聚簇索引为条件来查找数据,都能利用到”覆盖索引“这个特性,效率高。

聚簇的不足:1. 聚簇是数据在磁盘上的组织方式,所以只能带来磁盘IO上的收益,如果表的数据能全部载入内存,聚簇索引就没什么帮助了。2. 数据插入(Insert)的速度依赖于插入顺序——大量数据按照聚簇索引顺序插入会很快,如果乱序插入,就会比较慢,并且在大量乱序插入数据后,最好对表做一次rebuild操作。3. 更新聚簇索引字段的开销很大,因为系统不得不维护所有有关的页面。4. 聚簇的数据按照”页面“来存放,当一个列必须要放入一个已经满了的页面时,就会触发页面分裂——页面分裂会带来附加的IO开销,也会占用更多的磁盘空间。5. 在聚簇的表上做全表扫描会很慢,特别是数据的密集度很低(每个页面都有大量的空闲项)或因为多次页面分裂后,数据存放无序时。6. 非主键索引会比想象中的要大,因为非主键索引除了要存放索引字段,还需要一个指向聚簇索引的入口指针。7. 以非主键索引为条件访问不包含在索引中的字段时,需要做2次索引扫描。

The last point can be a bit confusing. Why would a secondary index require two index lookups? The answer lies in the nature of the "row pointers" the secondary index stores. Remember, a leaf node doesn't store a pointer to the referenced row's physical location; rather, it stores the row's primary key values.That means that to find a row from a secondary index, the storage engine first finds the leaf node in the secondary index and then uses the primary key values stored there to navigate the primary key and find the row. That's double work: two B-Tree navigations instead of one. (In InnoDB, the adaptive hash index can help reduce this penalty.)为什么非主键索引需要两次索引扫描?这关系到非主键索引的一个特性——行指针——非主键索引的叶子节点存放的不是指向数据行实际物理位置的指针,而是行的主键值。当按照非主键索引查找数据时,存储引擎首先按照非主键索引取得对应的”行指针“,然后再按照这个指针查询主键索引获取整行的值,所以产生了两次B-Tree查询。

书中原文以 cluster index和secondary index来区分两种索引,针对InnoDB,可以直接说成是主键和非主键。

原文地址:http://bbs.chinaunix.net/forum.php?mod=viewthread&tid=3639012&highlight=(感谢作者)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息