秒懂 MySQL 索引下推 一句话概括索引下推 索引下推的核心思想是:让索引层承担更多过滤工作,尽量减少对底层数据行的无效访问。这相当于优化了查询的工作流程,将部分过滤操作前置。 索引下推的通俗解释 我们可以用一个公司查询档案的场景来通俗地理解这个概念。 没有索引下推的传统方式 假设你是这样操作的:
索引下推的核心思想是:让索引层承担更多过滤工作,尽量减少对底层数据行的无效访问。这相当于优化了查询的工作流程,将部分过滤操作前置。
我们可以用一个公司查询档案的场景来通俗地理解这个概念。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
假设你是这样操作的:
你:人事同事,麻烦帮我找出所有年龄大于25岁的员工。
人事:好的,这是初步筛选出的500个员工的工号列表。
你:哦对了,我还需要他们必须是北京分公司的。
人事:这个条件我这边没法直接筛,你得自己拿着这500个工号,去档案室调出每个人的详细档案来核对。
你:好吧…这意味着我得跑500趟档案室,一份一份地翻看。
这里的问题在于:明明“分公司”这个筛选条件可以提前应用,却不得不进行大量重复的底层查询。
现在流程优化了:
你:人事同事,请帮我找年龄大于25岁并且是北京分公司的员工。
人事:明白。我这次可以一次性把两个条件都处理好,直接给你80个符合条件的员工工号。
你:太好了!这样我只需要跑80趟档案室。
效果非常明显:人事(相当于索引)在提供列表前就完成了额外筛选,让你少跑了420趟。这就是效率提升的来源。
将上面的比喻应用到具体的数据表和SQL上,可以理解得更透彻。假设有这样一张员工表:
-- 员工表,在 (年龄, 分公司) 上建有复合索引
CREATE TABLE 员工表 (
工号 INT PRIMARY KEY,
姓名 VARCHAR(50),
年龄 INT,
分公司 VARCHAR(50),
工资 DECIMAL(10,2),
INDEX idx_年龄_分公司 (年龄, 分公司)
);
接下来分析两种不同的查询执行过程:
-- 传统查询(没有索引下推) SELECT * FROM 员工表 WHERE 年龄 > 25 AND 分公司 LIKE '北京%'; -- 执行过程分析: -- 1. 使用索引找到所有年龄>25的记录(假设500条) -- 2. 根据这500条记录的工号(主键),逐一回表查询完整数据行(500次I/O) -- 3. 在内存中对这500条完整记录筛选“分公司 LIKE '北京%'”
-- 开启索引下推后 -- 执行过程分析: -- 1. 同样使用索引找到所有年龄>25的记录(500条) -- 2. **关键一步**:在索引层内部,直接对这批记录的“分公司”字段应用 LIKE '北京%' 条件进行过滤(剩80条) -- 3. 只对这80条满足所有索引列条件的记录进行回表查询(80次I/O)
索引下推让存储引擎变得更“聪明”。以前它通常只按最左前缀匹配,现在可以利用索引中包含的列做更多过滤:
分公司 = ‘北京’分公司 LIKE ‘北京%’年龄 BETWEEN 20 AND 30工资 > 10000(因为“工资”字段不在这个索引中)简单来说,就是过滤条件必须能被索引“看见”和处理。
-- 情况1:查询条件完全被复合索引覆盖 -- 表上有 (年龄, 城市) 索引 SELECT * FROM 用户 WHERE 年龄 > 20 AND 城市 LIKE '上海%'; -- 生效!“城市”在索引中,引擎可以在索引层完成LIKE过滤。 -- 情况2:查询条件全部是索引列 -- 表上有 (用户ID, 状态) 索引 SELECT * FROM 订单 WHERE 用户ID = 1001 AND 状态 = '已支付'; -- 生效!两个条件列都在索引中。
以下场景索引下推无法生效:
-- 情况1:查询已完全被索引覆盖,无需回表 -- 表上有 (姓名, 年龄) 索引 SELECT 姓名, 年龄 FROM 员工; -- 不需要!所需数据索引中全有,直接扫描索引即可(覆盖索引),谈不上“下推”。 -- 情况2:过滤条件涉及非索引列 -- 表上有 (年龄, 城市) 索引 SELECT * FROM 用户 WHERE 年龄 > 20 AND 工资 > 10000; -- 无效!“工资”字段不在索引中,引擎无法在索引层对其进行判断,只能回表后筛选。
传统执行方式: 索引范围扫描:定位到50万条索引记录(效率较高) 回表查询:进行50万次随机I/O读取完整行(耗时巨大) 服务层筛选:在50万条结果集中过滤“北京分公司”(消耗CPU和内存) 总耗时:约3.2秒 索引下推方式: 索引扫描与过滤:在扫描索引时同步过滤“分公司 LIKE '北京%'”,最终只锁定5万条索引项(扫描量略增,但过滤高效) 回表查询:仅对5万条记录进行回表(I/O压力骤减) 总耗时:约0.8秒
性能提升接近4倍!数据量越大,筛选性越强,提升效果越显著。
传统方式: 你:请找“作者=鲁迅”的书。 管理员:给你100本鲁迅著作的索书号。 你:再从中找出“小说类”的。 管理员:那得你自己去书架上把这100本都拿来翻看目录。 下推方式: 你:请直接找“作者=鲁迅 且 类别=小说”的书。 管理员:好的,这是30本符合要求的索书号。
传统方式: 先按“距离<3km”筛选出50家店。 然后你在这50家店里手动翻看“评分>4.5”的。 下推方式: 直接设置筛选条件:“距离<3km 且 评分>4.5”。 平台直接呈现15家符合条件的店铺。
-- MySQL 5.6及以上版本默认开启,通常无需手动设置。 -- 如何验证查询是否使用了索引下推? EXPLAIN SELECT ...; -- 查看Extra字段,如果出现“Using index condition”,说明索引下推正在生效。
| 适用场景 | 效果评级 | 原因分析 |
|---|---|---|
| 海量数据表筛选 | 回表成本极高,减少回表次数收益最大 | |
| 索引选择性高 | 能在索引层过滤掉大部分无效数据 | |
| 查询条件组合多 | 提前过滤能显著减轻后续处理负担 | |
| 小表或全表扫描 | 数据本身不多,优化空间有限 |
规律很直观:数据表越大,查询条件越复杂(且在索引中),索引下推带来的性能提升就越显著。
最后,通过一个实际场景检验一下理解程度:
如果要查询“年龄>30岁的北京分公司程序员”,但表上只有(年龄, 分公司)这个复合索引,并不包含“职位”字段。
请问,索引下推在这个过程中能起到什么作用?什么作用起不到?
参考答案:
可以看到,即使不能完全解决所有问题,但能提前做一点过滤,就绝不留到后面——这正是索引下推设计的智慧所在。它未必能给你百分百的答案,但能帮你把工作量降到最低。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述