MySQL 覆盖索引

内容纲要

file

概述

一个索引包含了所有需要查询的字段值,那么就称为覆盖索引。

好处

  • 索引的大小通常远小于数据行大小,所以如果只需要读取索引,那么MySQL会极大的减少数据访问量。
  • 索引是按照值得顺序存储的。
  • InnoDB使用聚集索引(Cluster Index),InnoDB的二级索引叶子节点中保存了行的主键值,所以如果二级索引能够覆盖查询,那么可以避免对主键索引的二次查询。

覆盖索引并不限定必须是某种类型的索引,它指的是一种查询优化方式:如果查询可以完全由索引来完成,并不需要访问实际的行数据,那么这样的查询称为覆盖索引查询,这样的索引就称为覆盖索引。

file

原理

MySQL InnoDB所有二级索引都是指向聚集索引,而不是直接指向行记录,这样在记录更新时只需要更新聚集索引和记录的关联就可以了。但是在MyISAM存储引擎中,所有索引都直接指向行记录,所以在更新行记录时所有索引都需要更新。
但在MySQL InnoDB存储引擎中,查询使用二级索引可能需要会标查询,回表时查询聚集索引,这样就进行了二次查询造成多次IO。

如下图所示:

Explain覆盖索引提示

当查询使用了覆盖索引,可以在EXPLAIN的Extra列看到"Using index"的信息。

实验

基于MySQL 8.0.x
表结构和索引情况:

MySQL [employees]> desc sys_user;
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int          | NO   | PRI | NULL    | auto_increment |
| name        | varchar(10)  | NO   |     | NULL    |                |
| name_pinyin | varchar(255) | NO   |     | NULL    |                |
| id_card     | varchar(255) | NO   | UNI | NULL    |                |
| phone       | varchar(20)  | YES  | MUL | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+
5 rows in set (0.07 sec)

MySQL [employees]> show indexes from sys_user;
+----------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------------------+---------+------------+
| Table    | Non_unique | Key_name        | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment             | Visible | Expression |
+----------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------------------+---------+------------+
| sys_user |          0 | PRIMARY         |            1 | id          | A         |        3494 |     NULL |   NULL |      | BTREE      |         |                           | YES     | NULL       |
| sys_user |          0 | uni_idx_id_card |            1 | id_card     | A         |        3494 |     NULL |   NULL |      | BTREE      |         | 唯一索引-身份证号         | YES     | NULL       |
| sys_user |          1 | idx_phone_name  |            1 | phone       | A         |        3493 |     NULL |   NULL | YES  | BTREE      |         | 普通索引-手机号           | YES     | NULL       |
| sys_user |          1 | idx_phone_name  |            2 | name        | A         |        3493 |     NULL |   NULL |      | BTREE      |         | 普通索引-手机号           | YES     | NULL       |
+----------+------------+-----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------------------+---------+------------+
4 rows in set (1.54 sec)

覆盖索引查询

  1. 从sys_user表中查询手机号和姓名
    explain select phone,name from sys_user;

    EXPLAIN 输出结果:

    
    MySQL [employees]> explain select phone,name from sys_user;
    +----+-------------+----------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
    | id | select_type | table    | partitions | type  | possible_keys | key            | key_len | ref  | rows | filtered | Extra       |
    +----+-------------+----------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
    |  1 | SIMPLE      | sys_user | NULL       | index | NULL          | idx_phone_name | 125     | NULL | 3494 |   100.00 | Using index |
    +----+-------------+----------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
    1 row in set, 1 warning (0.00 sec)

2. 从sys_user表中查询phone,name和id
```sql
explain select id, phone,name from sys_user;

EXPLAIN结果输出:

MySQL [employees]> explain select id, phone,name from sys_user;
+----+-------------+----------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
| id | select_type | table    | partitions | type  | possible_keys | key            | key_len | ref  | rows | filtered | Extra       |
+----+-------------+----------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | sys_user | NULL       | index | NULL          | idx_phone_name | 125     | NULL | 3494 |   100.00 | Using index |
+----+-------------+----------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

参考

  1. 高性能MySQL(第三版)

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部