MySql 索引(聚集索引,辅助索引,联合索引,覆盖索引..)

引入一个面试问题:

  • 查询一条数据 , 如果where 后面 有主键 ,有其他索引, mysql 会使用哪个去查询数据?

  • 为什么选择用主键查询数据?

  • 主键查询完成后 需要回表操作么?

看完以下以后再回顾,会发现迎刃而解

Mysql 可以为每一张表设置 存储引擎 这里我们只说 InnoDB 存储引擎.

聚集索引

InnoDB 存储引擎表 是索引组织表, 即 表中的数据 按照主键顺序存放。 而聚集索引,或者聚簇索引就是按照 表中的主键构造一颗B +树 ,(如果米有指定主键,那么 Mysql会自动生成一个6字节的rowId作为主键) , 同时 在它叶子节点中 存放,主键关联行的 数据, ,也就是说 每个主键会关联所在行的所有记录数据, 因此也将叶结点称为数据页。 所以 这个特性决定了 索引组织表中的数据,也是索引的一部分。 同B+树一样, 每个数据页都通过双向链表链接

由于实际情况,数据页只能按照一棵 B+树 进行排序, 因此每张表只能拥有一个 聚集索引(即 主键)。

  • 在多数情况下, 查询优化器 会优先查询 聚集索引或者说聚簇索引(主键), 因为可以通过该索引 直接在叶子节点上找到数据

  • 此外由于 定义了数据的逻辑范围,(按照主键顺序排序 ,数据页双向链表) 所以, 查询优化器可以迅速的发现一段范围的数据页需要扫描

栗子:

查询 一张注册用户的表, 获取最后十位注册的用户
​
select * from  register  order by  id DESC, limit 10;

聚集索引的一个好处就是, 它对于主键的排序和范围查找速度非常快。 而且 叶子节点关联 了主键对应行数据,所以不需要回表可以直接定位数据, 且 页节点的数据(数据页) 采用双向链表, 可以很方便的去往前 遍历数据

辅助索引

辅助索引也叫 非聚集索引(或者说非聚簇索引), 这类索引 叶子节点并不包含记录行数据。

每个叶子节点的索引行中包含了一个书签(bookmark). 该书签是用来告诉 InnoDB存储引擎哪里可以找到该索引对应的数据行或者说 行数据! 由于InnoDB存储引擎表, 是按照主键来构建的, 所以 ,该书签内其实包含或者说指向了 数据行所对应的聚集索引键

也就是说 辅助索引的 叶结点保存了 指向对应数据的 聚集索引, 可以通过该聚集索引 找到对应的数据行

辅助索引的存在并不影响数据在聚集索引中的组织,因为每张表上可以有多个辅助索引。

当通过辅助索引来寻找数据时,InnoDB 存储引擎会遍历辅助索引并通过叶级别的指针获得指向主键索引(聚集索引)的主键,然后再通过聚集索引找到一个完整的数据行。

例如:

如果在一棵高度为3 的辅助索引树中查找数据, 那么需要对这棵树进行3次遍历才能找到指定的聚集索引, 如果聚集索引树的高度也是3 , 那么还需要对该聚集索引树进行3次的查找,最终找到一个完整的行数据所在的页,因此一共需要6次 逻辑IO访问 得到一个最终的数据页

聚集索引辅助索引关系:


聚集索引辅助索引关系.PNG

联合索引

: 又叫做组合索引 ,辅助索引的一种, 和普通创建索引的方式一样,不同的是 可以同时添加多列来作为索引项;

从本质上来说,联合索引也是一课B+树

  • 索引中 使用多个列组成 的索引 如 index(id,name,age)

  • 组合索引 必须遵守最左原则: 即使用组合索引时 需要满足 最左原则 否则 索引不生效,即:查询时需要满足 必须存在索引列最左边的那一列的条件

个人理解:所谓最左原则, 是因为 存储引擎构建组合索引时 是根据最左边的那一列索引项进行排序的 ,所以使用组合索引,必须满足 条件中必须存在 最左边那一列的索引项,这样 才可以找到对应的索引,继而 去寻找对应的数据

覆盖索引

: 又叫做 索引覆盖,InnoDB中支持覆盖索引,即 从辅助索引中就可以得到查询的记录,而不需要查询聚集索引中的记录。

  • 使用覆盖索引的一个好处就是,由于本身不会包含完整行数据(辅助索引 只包含 主键的一些信息 比如 key)

    所以大小要远远小于聚集索引,且由于可以从本身直接获取到想要的数据,无需回表查询,可以大大加快查询速度,减少大量IO 操作

对于 组合 索引  (id,ke2,ke3)
​
select ke2 from table where id=xxx;
select ke2,key3 from table where id=xxx;
​
等等.. 都可以使用一次辅助联合索引 来完成查询,这其中就是覆盖索引,,可以直接获取数据而无需回索引表查询
​
select count(*) from table;
InnoDB 存储引擎是不会查询聚集索引来进行统计, 由于存在辅助索引,而辅助索引远小于聚集索引,选择辅助索引可以减少IO操作,所以优化器会选择 辅助索引来进行统计

通常情况下: 联合索引不满足 最左原则的话,优化器是不会选择使用 该索引的,但是如果是 使用聚合函数比如 count(*) 进行统计, 且是可以利用到覆盖索引的,则优化器会进行选择

比如 这里没有根据最左原则使用组合索引,但是 优化器依然进行选择

mysql> desc select count(*) from student where age>10 and age <20;
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
| id | select_type | table   | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | student | NULL       | index | id            | id   | 52      | NULL |    9 |    11.11 | Using where; Using index |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.01 sec)

回表

即 : 所谓回表,就是 辅助索引 查找数据时, 获取到对应的主键以后,根据主键扫描另一棵索引树(根据主键查询聚集索引表)来获取数据
因此,上面面试题中 ,主键查询完成以后不需要回表,因为 使用了聚集索引,可以直接在叶结点获取对应数据

共勉,欢迎指导谢谢~

你可能感兴趣的:(MySql 索引(聚集索引,辅助索引,联合索引,覆盖索引..))