覆盖索引 covering index

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 覆盖索引定义 应用场景 测试

简介

覆盖索引是InnoDB中索引的特例,索引中包含查询的所有必填字段;换句话说,索引本身包含执行查询所需的数据,而不必执行额外的读取。

请注意,在InnoDB中,数据是使用主键索引存储的。换句话说,数据通过主键索引物理地存储为B +树。因此,主键被包括在所有二级索引的叶节点中以便建立从二级索引到实际数据行的引用。

因此,任何涉及二级索引的查找都必须从根节点通过分支节点导航到正确的叶节点以获取主键值,然后对主键索引执行随机IO读取(再次从根节点通过分支节点到正确的叶节点)来获取数据行。

使用覆盖索引,我们避免了在主键索引(一个B +树较少遍历,避免昂贵的IO操作)上的这种额外的随机IO读取以获取数据行,因为查询所需的所有字段都包括在覆盖索引中。

什么时候使用覆盖索引

  • 避免大表额外的IO读取。有时甚至可以避免额外的物理随机IO读取(最昂贵的IO操作)。
    我们可以使用这个特定的索引进行查询,需要:

过滤符合一定条件的行(WHERE子句)
分组数据(GROUP BY子句)
按覆盖索引(ORDER BY子句)的顺序排序数据
投影数据(SELECT子句)

测试

创建测试表

CREATE TABLE big_table(

  id int primary key auto_increment,

  field01 int,

  field02 int,

  field03 varchar(50)
) engine=innodb;

循环插入数据1kw数据

insert into big_table( field01, field02, field03) SELECT FLOOR(RAND() * 10000),FLOOR(RAND() * 10000),MD5(RAND() * 1000);

测试SQL:

select sum(field02) from big_table  group by field01 limit 10;

不建立索引情况下耗时

mysql> show index from big_table;
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| big_table |          0 | PRIMARY  |            1 | id          | A         |     8941508 |     NULL | NULL   |      | BTREE      |         |               |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)

mysql> explain select sum(field02) from big_table  group by field01 limit 10;
+----+-------------+-----------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+
| id | select_type | table     | partitions | type | possible_keys | key  | key_len | ref  | rows    | filtered | Extra                           |
+----+-------------+-----------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+
|  1 | SIMPLE      | big_table | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 9294102 |   100.00 | Using temporary; Using filesort |
+----+-------------+-----------+------------+------+---------------+------+---------+------+---------+----------+---------------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> select sum(field02) from big_table  group by field01 limit 10;
+--------------+
| sum(field02) |
+--------------+
|  47205571014 |
|        68956 |
|       100295 |
|        83829 |
|        71500 |
|        87253 |
|        66426 |
|        59674 |
|        62528 |
|        51620 |
+--------------+
10 rows in set (4.19 sec)

建立单个field01及field02索引

mysql> create index idx_f2 on big_table(field02);
Query OK, 0 rows affected (18.64 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> create index idx_f1 on big_table(field01);
Query OK, 0 rows affected (13.36 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql>  show index from big_table;
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| big_table |          0 | PRIMARY  |            1 | id          | A         |     8941508 |     NULL | NULL   |      | BTREE      |         |               |
| big_table |          1 | idx_f2   |            1 | field02     | A         |       10669 |     NULL | NULL   | YES  | BTREE      |         |               |
| big_table |          1 | idx_f1   |            1 | field01     | A         |       10206 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

mysql> explain  select sum(field02) from big_table  group by field01 limit 10;
+----+-------------+-----------+------------+-------+---------------+--------+---------+------+------+----------+-------+
| id | select_type | table     | partitions | type  | possible_keys | key    | key_len | ref  | rows | filtered | Extra |
+----+-------------+-----------+------------+-------+---------------+--------+---------+------+------+----------+-------+
|  1 | SIMPLE      | big_table | NULL       | index | idx_f1        | idx_f1 | 5       | NULL | 9106 |   100.00 | NULL  |
+----+-------------+-----------+------------+-------+---------------+--------+---------+------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> select sum(field02) from big_table  group by field01 limit 10;
+--------------+
| sum(field02) |
+--------------+
|  47205571014 |
|        68956 |
|       100295 |
|        83829 |
|        71500 |
|        87253 |
|        66426 |
|        59674 |
|        62528 |
|        51620 |
+--------------+
10 rows in set (16.86 sec)

有没有发现建立索引的情况下反而比全表扫描慢很多,读者可以自己去思考。其实本质上这种类型的sql全表扫描是一种比较快速的方式

建立联合索引covering index

mysql> create index idx_f12 on big_table(field01,field02);
Query OK, 0 rows affected (24.42 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from big_table;
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table     | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| big_table |          0 | PRIMARY  |            1 | id          | A         |     8941508 |     NULL | NULL   |      | BTREE      |         |               |
| big_table |          1 | idx_f12  |            1 | field01     | A         |       10019 |     NULL | NULL   | YES  | BTREE      |         |               |
| big_table |          1 | idx_f12  |            2 | field02     | A         |      328573 |     NULL | NULL   | YES  | BTREE      |         |               |
+-----------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

mysql> explain select sum(field02) from big_table  group by field01 limit 10;
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table     | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | big_table | NULL       | index | idx_f12       | idx_f12 | 10      | NULL |   10 |   100.00 | Using index |
+----+-------------+-----------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> select sum(field02) from big_table  group by field01 limit 10;
+--------------+
| sum(field02) |
+--------------+
|  47205571014 |
|        68956 |
|       100295 |
|        83829 |
|        71500 |
|        87253 |
|        66426 |
|        59674 |
|        62528 |
|        51620 |
+--------------+
10 rows in set (2.04 sec)
比不加索引的情况下快了一倍左右。

参考

link

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
|
SQL 存储 索引
12. 知道什么叫覆盖索引嘛 ?
**覆盖索引**是指在SQL查询中,索引包含所有所需列数据,避免回表查询,提高效率。创建覆盖索引可通过为查询字段建立联合索引,如在`user`表上为`name`和`age`创建`index_name_age`索引。查询`select name,age from user where name='Alice'`时,索引中已包含`name`和`age`,直接返回结果,实现覆盖索引。
58 0
12. 知道什么叫覆盖索引嘛 ?
|
4月前
|
存储 关系型数据库 MySQL
第8章 索引index
第8章 索引index
33 0
|
存储 关系型数据库 MySQL
什么是覆盖索引?
本章主要讲解了索引覆盖和回表的相关知识
126 0
|
数据库 索引
覆盖索引
覆盖索引是指在数据库中创建一个索引,使得查询可以直接从索引中获取所需的数据,而不需要再去访问数据表。这种索引能够减少数据库的I/O操作,提高查询的性能。
73 0
|
6月前
|
存储 算法 关系型数据库
十五、索引 (Index)
十五、索引 (Index)
71 0
|
6月前
|
索引
根据索引值计算item所在行列(row,col)索引序号(index)
根据索引值计算item所在行列(row,col)索引序号(index)
|
SQL 关系型数据库 MySQL
好的索引当然是要覆盖了!
好的索引当然是要覆盖了!
|
索引
索引分类、创建索引、删除索引
索引分类、创建索引、删除索引
137 0
索引分类、创建索引、删除索引
|
存储 关系型数据库 MySQL
MySQL 覆盖索引(Cover Index)
MySQL 覆盖索引(Cover Index)
260 0
MySQL 覆盖索引(Cover Index)
|
关系型数据库 MySQL 数据库
创建索引,这些知识应该了解
在 MySQL 中,基本上每个表都会有索引,有时候也需要根据不同的业务场景添加不同的索引。索引的建立对于数据库高效运行是很重要的,本篇文章将介绍下创建索引相关知识及注意事项。
144 0