覆盖索引 covering index

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
云数据库 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

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
12月前
|
存储 关系型数据库 MySQL
介绍一下MySQL的一些应用场景
【10月更文挑战第17天】介绍一下MySQL的一些应用场景
2479 0
|
10月前
|
存储 人工智能 自然语言处理
效率翻倍!2024免费AI流程图生成工具评测
2分钟了解有哪些好用的AI流程图生成工具。
1479 4
效率翻倍!2024免费AI流程图生成工具评测
|
消息中间件 存储 监控
Java一分钟之-ActiveMQ:消息中间件
【6月更文挑战第11天】Apache ActiveMQ是广泛使用的开源消息中间件,支持JMS和多种消息协议。本文介绍了ActiveMQ的基础知识,包括消息队列和主题模型,以及持久化和高可用性配置。同时,提出了三个常见问题:配置不当、消息堆积和网络错误,并给出了相应的解决策略。通过Java示例代码展示了如何使用ActiveMQ发送和接收消息。正确配置、管理消息处理和持续监控是确保ActiveMQ高效运行的关键。
311 2
|
JSON 关系型数据库 MySQL
mysqlx_max_connections
mysqlx_max_connections
1228 0
|
数据采集 中间件 调度
Scrapy:高效的网络爬虫框架
Scrapy是Python的网络爬虫框架,用于快速构建和开发爬虫。它提供简单API和全功能环境,包括请求调度、HTML解析、数据存储等,让开发者专注爬虫逻辑。Scrapy工作流程包括发起请求、下载响应、解析数据、处理数据和发送新请求。其核心组件有调度器、下载器、解析器(Spiders)和Item Pipeline,广泛应用于数据挖掘、信息监测、搜索引擎和自动化测试。有效技巧包括合理设置请求参数、编写高效解析器、使用代理和防反爬策略,以及利用中间件。随着大数据和AI的发展,Scrapy在爬虫领域的地位将持续巩固。【6月更文挑战第6天】
488 0
|
人工智能 自然语言处理 安全
搭建微信公众号AI助手
将微信公众号(订阅号)变为AI智能客服仅需四步:创建大模型问答应用、搭建微信公众号连接流、引入AI智能客服及增加私有知识。首先在百炼平台创建应用并获取API密钥;其次利用阿里云AppFlow服务无代码连接微信公众号与大模型应用;接着配置公众号引入AI客服;最后上传企业知识文档提升客服精准度。通过这些步骤,轻松实现智能化客户服务。
1242 2
|
机器学习/深度学习 算法
【MATLAB】GA_BP神经网络回归预测算法
【MATLAB】GA_BP神经网络回归预测算法
349 3
【MATLAB】GA_BP神经网络回归预测算法
|
设计模式 Java
Java设计模式之桥接模式详解
Java设计模式之桥接模式详解
|
存储 消息中间件 算法
深度思考:架构师必须掌握的五大类架构设计风格
数据流风格注重数据在组件间的流动,适合处理大量数据。调用返回风格则强调函数或方法的调用与返回,过程清晰明了。独立构件风格让每个构件独立运作,通过接口交互,提升灵活性和可重用性。虚拟机风格则模拟完整系统,实现资源的高效利用。
744 0
深度思考:架构师必须掌握的五大类架构设计风格
|
前端开发 Java Spring
SpringBoot通过拦截器和JWT令牌实现登录验证
该文介绍了JWT工具类、匿名访问注解、JWT验证拦截器的实现以及拦截器注册。使用`java-jwt`库生成和验证JWT,JwtUtil类包含generateToken和verifyToken方法。自定义注解`@AllowAnon`允许接口匿名访问。JwtInterceptor在Spring MVC中拦截请求,检查JWT令牌有效性。InterceptorConfig配置拦截器,注册并设定拦截与排除规则。UserController示例展示了注册、登录(允许匿名)和需要验证的用户详情接口。
2013 1