mysql的索引策略中有一条是聚簇索引,而聚簇索引并不是唯一索引,普通索引之类的索引类型,而是一种数据的存储方式。大多数索引存在的形式为B-tree,叶子节点的索引则和其对应的数据行数据紧凑的存储在一起,这就是术语聚簇的含义。实现数据存储形式的是存储引擎,但并不是所有存储引擎都支持聚簇索引,而著名的InnoDB则是支持的引擎之一,下面都以InnoDB为例。
-
聚簇索引的建立
而存储引擎不能管理两份同样的数据,所以聚簇索引在同一张数据表中只能存在一个,其他的索引只能是非聚簇索引,也就是二级索引。数据表的如果有指定primary key,那么InnoDB就会把primary key作为聚簇索引来存储,如果没有,则会取第一个not null,unique的索引作为聚簇索引,unique的索引也不存在的话,InnoDB就会自行的,隐式的指定一个row ID列作为聚簇索引存储,但这个row ID不会被用户管理。
-
聚簇索引的优劣
聚簇索引一些重要的优点:
1. 在有聚簇索引的数据表中,使用聚簇索引进行查询的时候,因为索引和数据聚集在同一个B-tree中,能够直接从索引获取到数据行,比非聚簇索引的性能要好。
2. 反之在没有聚簇索引的数据表中,因为不能通过unique的值去聚集数据,所以需要通过非聚簇索引查询数据的物理地址或者全表扫描来获取数据,这样每一行数据可能都会导致一次磁盘I/O。
在提升性能的同时,聚簇索引也存在着缺点:
1. 更新聚簇索引的代价会很大,因为需要将数据行和主键进行重排,移动到新的位置,并且二级索引可能也需要更新。
2. 聚簇索引的插入速度严重依赖插入顺序,严格的升序主键是性能最好的方式,但如果主键是乱序的插入,例如用uuid作为主键,当主键值需要插入到某一页已经写满的page中,存储引擎就需要将page分裂成两个页面来容纳数据,这一个页分裂(page split)
操作,page split会使得数据表占用更多的磁盘空间。
3. 通过二级索引获取需要两次索引查找,因为二级索引保存的是聚簇索引的主键,而不是指向数据的逻辑指针,所以获取主键后需要再进行一次搜索才能获取数据。
-
聚簇索引和二级索引对比
聚簇索引和二级索引的数据分布方式不同,在MyISAM和InnoDB的数据文件组织方式中也有体现。
MyISAM的数据由3个文件组成:1. .frm(表结构描述文件)
,2. .MYD(数据行文件)
,3. .MYI(索引文件)
。
InnoDB则有2个文件:1. .frm(表结构描述文件)
,2. .MYD(数据行文件和索引信息)
。
MyISAM引擎没有使用索引和数据的聚集的分布方式,所以主键和其他索引的是没有区别,就都存储在索引文件中。
InnoDB的锁机制是使用索引来实现,表现的等级为行级锁,而MyISAM则是表级锁,这也跟数据分布方式有关。InnoDB的主键索引与数据紧凑的聚集在一起,并且包含了事务ID,用于事务MVCC的回滚指针,而MyISAM则是数据与索引分离,无法实现如此细粒度的锁。
-
聚簇索引的注意事项
1. InnoDB暂时不能由用户选定索引作为聚簇索引,InnoDB有自己的聚簇索引选取规则,所以在创建表的时候最好设置一个与业务无关的主键id作为聚簇索引,这样修改二级索引和数据的时候,无需移动数据位置,提升性能。
2. 聚簇索引的主键id不要使用uuid,uuid会使得数据的插入添加额外的页分裂操作,降低性能,最好使用单调自增的id。