当前位置: 首页 > news >正文

MySQL索引(二):覆盖索引、最左前缀原则与索引下推详解

MySQL系列文章

本文是MySQL索引系列的第二篇,接续前文《MySQL索引(一):从数据结构到存储引擎的实现》的基础知识,将深入探讨索引的高级特性和优化技巧。本文将通过实际案例,详细解析覆盖索引、最左前缀原则和索引下推这三个核心优化技术。

在数据库性能优化中,合理使用索引是最有效的手段之一。前文我们介绍了索引的基本数据结构和工作原理,今天我们将继续探索MySQL索引的三个特性:覆盖索引最左前缀原则索引下推,这些特性能够显著提升查询性能。

实战场景:订单查询的性能优化

让我们从一个实际的业务场景开始。假设我们有一个电商平台的订单表,结构如下:

CREATE TABLE `orders` (`order_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,`user_id` INT NOT NULL,`product_id` INT NOT NULL,`order_time` DATETIME NOT NULL,`amount` DECIMAL(10,2) NOT NULL,`status` TINYINT NOT NULL DEFAULT 0,`remark` VARCHAR(200) DEFAULT NULL,PRIMARY KEY (`order_id`),KEY `idx_user_time` (`user_id`, `order_time`),KEY `idx_product` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

现在有一个高频查询:获取某个用户最近一个月的订单记录,只需要订单ID、用户ID、下单时间和订单金额。

SELECT order_id, user_id, order_time, amount 
FROM orders 
WHERE user_id = 1001 AND order_time >= '2023-05-01' AND order_time < '2023-06-01';

这个查询会如何使用索引?是否存在优化空间?让我们一起来分析。

一、覆盖索引:避免回表的性能提升

什么是覆盖索引?

覆盖索引是指一个索引包含了查询所需的所有字段,MySQL可以直接从索引中获取需要的数据,而无需回表查询数据行。这就像是一本教科书,如果目录已经包含了你要找的全部信息,就不需要翻到正文页面了。

覆盖索引的优势

  1. 减少IO操作:避免回表操作,减少磁盘IO
  2. 提升查询速度:索引数据通常比行数据小,且更可能缓存在内存中
  3. 减少内存占用:只需要加载索引数据,不需要加载整行数据

实战优化

在我们的订单表例子中,现有索引idx_user_time包含了user_idorder_time,但查询还需要amount字段。为了使用覆盖索引,我们可以创建新索引:

ALTER TABLE orders ADD INDEX idx_user_time_amount (user_id, order_time, amount);

现在执行同样的查询,使用EXPLAIN分析执行计划:

EXPLAIN SELECT order_id, user_id, order_time, amount 
FROM orders 
WHERE user_id = 1001 AND order_time >= '2023-05-01' AND order_time < '2023-06-01';

EXPLAIN结果分析:

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEordersNULLrangeidx_user_time,idx_user_time_amountidx_user_time_amount9NULL156100.00Using where; Using index

从EXPLAIN结果可以看到:

  • key字段显示使用了idx_user_time_amount索引
  • Extra字段显示"Using index",表示使用了覆盖索引
  • key_len为9,表示索引使用了9字节(user_id占4字节,order_time占5字节)

提示key_len表示查询实际使用索引的字节长度,可以判断联合索引使用深度。

详细解读请参考我的另一篇文章:《MySQL EXPLAIN中的key_len终极指南》

关于DATETIMEMySQL 5.6.4 是分水岭:此前固定占用 8 字节;此后优化为 5 字节基础 + 精度附加空间

覆盖索引的使用建议

  • 针对高频查询,设计专门的覆盖索引
  • 将WHERE条件中的字段和SELECT需要的字段都包含在索引中
  • 注意索引长度,避免创建过大的联合索引

二、最左前缀原则:索引设计的艺术

理解最左前缀原则

最左前缀原则是B+树索引的重要特性:索引可以用于查询条件匹配索引最左前缀的查询。就像电话簿按"姓+名"排序,你可以快速找到所有姓"张"的人,但要找名为"三"的人就需要全表扫描。

最左前缀原则定义这个最左前缀可以是联合索引的最左N个字段,也可以是字符串索引的最左M个字符

最左前缀的实际应用

在我们的订单表中,索引idx_user_time(user_id, order_time)可以用于:

  1. WHERE user_id = 1001(使用部分索引)
  2. WHERE user_id = 1001 AND order_time > '2023-01-01'(使用完整索引)
  3. WHERE user_id = 1001 ORDER BY order_time(索引天然排序,避免filesort)
  4. WHERE order_time > '2023-01-01'(不能使用索引)
  5. WHERE amount > 1000(不能使用索引)

联合索引字段顺序设计原则

在建立联合索引的时候,如何安排索引内的字段顺序?第一原则是:如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的。

索引设计的最佳实践

  1. 选择性高的字段放在前面
    选择性高的字段(唯一值多的字段)放在联合索引前面,能更有效地过滤数据

  2. 考虑查询频率
    高频查询条件应该优先考虑放在索引前面

  3. 避免冗余索引
    已有索引(a,b,c)时,索引(a,b)通常是冗余的

  4. 注意索引长度
    字符串字段索引时,考虑使用前缀索引减少索引大小

实战案例优化

假设我们有以下查询模式:

  1. 按用户查询订单(高频)
  2. 按状态和用户查询订单(中频)
  3. 按状态查询订单(低频)

最优索引设计:

-- 好的设计:既能满足用户查询,也能满足用户+状态查询
ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);-- 同时添加索引
ALTER TABLE orders ADD INDEX idx_status_user (status);

通过合理设计联合索引字段顺序,我们可以用更少的索引满足更多的查询需求,这正是"通过调整顺序,少维护一个索引"原则的实际应用。

三、索引下推:减少回表次数

什么是索引下推?

索引下推(Index Condition Pushdown,简称ICP)是MySQL 5.6引入的重要优化。它允许在索引遍历过程中就进行条件过滤,而不是等到回表后再过滤。

索引下推的工作原理

没有索引下推时的查询流程:

  1. 使用索引定位记录
  2. 回表读取完整数据行
  3. Server层过滤数据

有索引下推时的查询流程:

  1. 使用索引定位记录
  2. 存储引擎层进行条件过滤
  3. 只对满足条件的记录回表

索引下推的性能影响

索引下推可以显著减少回表次数,特别是当索引条件能够过滤掉大量数据时。在我们的订单表例子中,如果查询条件包含索引和非索引字段:

-- 添加联合索引
ALTER TABLE orders ADD INDEX idx_user_remark (user_id, remark);SELECT * FROM orders 
WHERE user_id = 1001 AND remark LIKE '%重要%';

没有索引下推时:需要先找到所有user_id=1001的记录,回表后检查remark字段。

有索引下推时:存储引擎会在索引层面先过滤user_id=1001的记录,同时对能够判断的条件进行过滤,减少回表次数。

ICP的核心机制是“就地取材,提前过滤”。它允许存储引擎直接利用当前索引中的数据,在执行回表前就对WHERE条件中的部分条件进行过滤。

其生效的关键在于要过滤的条件字段必须包含在正在使用的索引中,从而最大限度地减少不必要的回表操作,提升查询性能。

  • 对于单列索引,只能对涉及该索引字段的额外条件进行下推。
  • 对于联合索引,ICP的能力最强,可以对索引中包含的多个字段的条件进行下推,效益最大化。

让我们用EXPLAIN验证索引下推的效果:

EXPLAIN SELECT * FROM orders 
WHERE user_id = 1001 AND status = 1 AND remark LIKE '%test%';

EXPLAIN结果分析:

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEordersNULLrefidx_user_remarkidx_user_remark4const2311.11Using index condition

Extra字段中的"Using index condition"表示使用了索引下推优化。

索引下推的使用限制

不是所有条件都适合下推:

  • 只能下推到存储引擎层的条件
  • 某些函数和表达式不能下推
  • 需要存储引擎支持(InnoDB支持索引下推)

四、综合实战:索引优化方案

回到我们的订单表,综合考虑各种查询需求:

常见查询场景:

  1. 按用户查询订单(覆盖索引:user_id, order_time, amount)
  2. 按产品查询订单,并按订单时间排序(索引天然有序,无需使用filesort)
  3. 按状态查询订单(状态字段区分度不高,但有时也必要)

优化后的索引方案:

-- 主键索引(聚簇索引)
PRIMARY KEY (order_id)-- 覆盖用户查询(遵循最左前缀原则)
ALTER TABLE orders ADD INDEX idx_user_cover (user_id, order_time, amount);-- 产品查询(考虑产品查询频率)
ALTER TABLE orders ADD INDEX idx_product_cover (product_id, order_time);-- 状态查询(低频,但需要时有效)
ALTER TABLE orders ADD INDEX idx_status (status);

五、索引设计的最佳实践总结

  1. 理解业务查询模式
    分析实际业务中的高频查询,针对性设计索引

  2. 优先使用覆盖索引
    减少回表操作,提升查询性能

  3. 合理利用最左前缀
    设计联合索引时考虑字段顺序和查询模式,遵循"少维护索引"原则

  4. 启用索引下推
    MySQL 5.6+默认启用,确保充分利用此特性

  5. 善用EXPLAIN分析
    使用EXPLAIN分析查询计划,关注key_len判断索引使用深度

  6. 定期审查和优化
    定期分析慢查询日志,优化索引策略

  7. 平衡读写性能
    索引不是越多越好,需要权衡读写性能

  8. 监控索引使用情况
    使用Performance Schema监控索引使用效率

结语

索引优化是数据库性能调优的核心环节,也是一个需要持续学习和实践的过程。通过合理使用覆盖索引、最左前缀原则和索引下推技术,我们可以显著提升查询性能,减少系统资源消耗。

在实际工作中,建议:

  1. 深入分析业务查询模式,针对性设计索引
  2. 熟练使用EXPLAIN分析查询执行计划,针对联合索引,特别关注key_len和Extra字段
  3. 遵循"通过调整顺序,少维护一个索引"的设计原则
  4. 建立慢查询监控机制,持续优化索引策略
  5. 定期审查索引使用情况,删除冗余和无效索引

记住,没有万能索引方案,最适合的索引设计来自于对业务需求和数据特征的深入理解。希望本文介绍的覆盖索引、最左前缀原则和索引下推技术,能够帮助你在实际工作中设计出更高效的索引方案,提升数据库查询性能。


文章转载自:

http://ZT6G4XGi.frsrk.cn
http://yZzIi0sG.frsrk.cn
http://TOujAlzB.frsrk.cn
http://ajbGKGki.frsrk.cn
http://b5UWyeGN.frsrk.cn
http://wjuC6tsN.frsrk.cn
http://xCzFBXs6.frsrk.cn
http://vllqK3lr.frsrk.cn
http://BJALl9hY.frsrk.cn
http://1xZz1E13.frsrk.cn
http://bZVvvIiv.frsrk.cn
http://y1vsg7P7.frsrk.cn
http://YDQxAgFt.frsrk.cn
http://oBGyUqAe.frsrk.cn
http://dF7Qnq1R.frsrk.cn
http://hNyFf5as.frsrk.cn
http://AUKIhS38.frsrk.cn
http://opGJSi5i.frsrk.cn
http://pV21akQO.frsrk.cn
http://dG7XUM0b.frsrk.cn
http://ktm1PaHE.frsrk.cn
http://uSZ6R19c.frsrk.cn
http://4AGIfnpC.frsrk.cn
http://55hwm9ot.frsrk.cn
http://rghmIhCG.frsrk.cn
http://kR2MaXq5.frsrk.cn
http://6fu1zMCY.frsrk.cn
http://FPOqauBU.frsrk.cn
http://TSbXwNRY.frsrk.cn
http://gMPBkXOM.frsrk.cn
http://www.dtcms.com/a/378492.html

相关文章:

  • 【WS63】星闪开发资源整理
  • 守住矿山 “生命线”!QB800系列在线绝缘监测在矿用提升机电传系统应用方案
  • Altium Designer(AD)原理图更新PCB后所有器件变绿解决方案
  • DIFY 项目中通过 Makefile 调用 Dockerfile 并使用 sudo make build-web 命令构建 web 镜像的方法和注意事项
  • 联合索引最左前缀原则原理索引下推
  • 平衡车 -- 速度环
  • BPE算法深度解析:从零到一构建语言模型的词元化引擎
  • DIPMARK:一种隐蔽、高效且具备鲁棒性的大语言模型水印技术
  • mysql多表联查
  • 审美积累 | 移动端仪表盘
  • 面阵结构光3D相机三维坐标计算
  • 【大前端++】几大特征
  • 【持续更新】高质量的项目开发过程(C++)(前后端)
  • 淘宝商品视频批量自动化获取的常见渠道分享
  • ABAP 将多层json逐层解析转成内表
  • 一样的糖果
  • linux x86_64中打包qt
  • Windows 10 22H2 64位 【原版+优化版、版本号:19045.6332】
  • 学习日记-CSS-day53-9.11
  • 线程的创建.销毁
  • pg卡死处理
  • 装饰器模式在Spring中的案例
  • 【Springboot】介绍启动类和启动过程
  • 服务器内部信息获取
  • 软考 系统架构设计师系列知识点之杂项集萃(143)
  • BFD原理与配置
  • spring源码分析————ListableBeanFactory
  • InfoSecWarrior CTF 2020: 02靶场渗透
  • wikijs如何增加全文搜索的功能,增加对应的索引(Win11环境+docker+数据库elasticSearch)
  • 企业远程访问方案选择:何时选内网穿透,何时需要反向代理?