聚集索引

聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。一个表只能有一个聚集索引,因为一个表的物理顺序只有一种情况,所以,对应的聚集索引只能有一个。如果某索引不是聚集索引,则表中的行物理顺序与索引顺序不匹配,与非聚集索引相比,聚集索引有着更快的检索速度。

注意:聚集索引也称为聚簇索引(Clustered Index)

聚集索引确定表中数据的物理顺序。聚集索引类似于字典,按字母排序,每个字母下有多个字(相当于数据列)。所以对于聚集索引,叶子结点即存储了真实的数据行。所以通过聚集索引可以直接获取到数据库中的数据。

注意:一般建表的时候,数据库就会为主键建立了聚簇索引



非聚集索引

该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同。

非聚集索引的叶层不包含数据页, 叶结点包含索引字段值及指向数据页数据行的逻辑指针(每个索引行包含非聚集键值以及一个或多个行定位器,这些行定位器指向有该键值的数据行(如果索引不唯一,则可能是多行))。所以非聚集索引不能直接获取到数据,需要通过定位器来获取数据。

聚集索引适用情况

1、含有大量非重复值的列。
2、使用BETWEEN,>,>=,<或<=返回一个范围值的列
3、被连续访问的列
4、返回大型结果集的查询
5、经常被使用连接或GROUP BY子句的查询访问的列

下面的表总结了何时使用聚集索引或非聚集索引:

kibana集成索引 聚集索引_mysql



MySQl中的实现

接下来,我们来看一下MySQL两种储存引擎的底层实现

MyISAM 引擎(非聚集索引方式)

MyISAM 用的是非聚集索引方式,即数据和索引落在不同的两个文件上。MyISAM 在建表时以主键作为 KEY 来建立主索引 B+树,树的叶子节点存的是对应数据的物理地址。我们拿到这个物理地址后,就可以到 MyISAM 数据文件中直接定位到具体的数据记录了。

kibana集成索引 聚集索引_mysql_02

当我们为某个字段添加索引时,我们同样会生成对应字段的索引树,该字段的索引树的叶子节点同样是记录了对应数据的物理地址,然后也是拿着这个物理地址去数据文件里定位到具体的数据记录。




Innodb 引擎(聚集索引方式)

InnoDB 是聚集索引方式,因此数据和索引都存储在同一个文件里。首先 InnoDB 会根据主键 ID 作为 KEY 建立索引 B+树,如左下图所示,而 B+树的叶子节点存储的是主键 ID 对应的数据,比如在执行 select * from user_info where id=15 这个语句时,InnoDB 就会查询这颗主键 ID 索引 B+树,找到对应的 user_name=‘Bob’。

这是建表的时候 InnoDB 就会自动建立好主键 ID 索引树,这也是为什么 Mysql 在建表时要求必须指定主键的原因。当我们为表里某个字段加索引时 InnoDB 会怎么建立索引树呢?比如我们要给 user_name 这个字段加索引,那么 InnoDB 就会建立 user_name 索引 B+树,节点里存的是 user_name 这个 KEY,叶子节点存储的数据的是主键 KEY。注意,叶子存储的是主键 KEY!拿到主键 KEY 后,InnoDB 才会去主键索引树里根据刚在 user_name 索引树找到的主键 KEY 查找到对应的数据。

kibana集成索引 聚集索引_kibana集成索引_03

问题来了,为什么 InnoDB 只在主键索引树的叶子节点存储了具体数据,但是其他索引树却不存具体数据呢,而要多此一举先找到主键,再在主键索引树找到对应的数据呢?

其实很简单,因为 InnoDB 需要节省存储空间。一个表里可能有很多个索引,InnoDB 都会给每个加了索引的字段生成索引树,如果每个字段的索引树都存储了具体数据,那么这个表的索引数据文件就变得非常巨大(数据极度冗余了)。从节约磁盘空间的角度来说,真的没有必要每个字段索引树都存具体数据,通过这种看似“多此一举”的步骤,在牺牲较少查询的性能下节省了巨大的磁盘空间,这是非常有值得的。