mysql覆盖索引是什么_mysql查询优化技巧

1次阅读

覆盖索引指查询所需字段全部被索引包含,无需回表;判断依据是explain中extra显示“using index”;建索引需按where→select顺序组织字段,并避免函数、类型转换等导致失效。

mysql覆盖索引是什么_mysql查询优化技巧

覆盖索引就是“查什么,索引里就有什么”

mysql 执行查询时,如果 SELECT 列和 WHERE 条件列全部被一个索引“包圆”了,连回表(去聚簇索引找完整行)都不用,那就叫覆盖索引。它不是某种特殊索引类型,而是**一种使用方式**——你建的普通 B+Tree 索引,只要字段选得准,就能变成覆盖索引。

关键判断依据是 EXPLAIN 输出中的 Extra 列:出现 Using index 就说明命中了覆盖索引;如果写 SELECT * 或漏了某列,哪怕只差一个字段,也会退化为 Using index condition 或更糟的 Using where; Using filesort

怎么建才能让索引真正“覆盖”你的查询

核心原则是:把 WHERE 条件字段放前面,SELECT 字段放后面,且不冗余、不遗漏。

  • 错误示范:CREATE INDEX idx_on_age_name ON users(age, name) 用于 SELECT name, city FROM users WHERE age > 25 —— city 没进索引,必然回表
  • 正确做法:CREATE INDEX idx_on_age_name_city ON users(age, name, city),顺序按“过滤 → 排序 → 返回”逻辑组织
  • 注意:InnoDB 的二级索引叶子节点天然存主键值,所以如果你查的是 SELECT id, name FROM users WHERE age = 30,即使索引只建了 (age, name),也能覆盖——因为 id 是主键,自动附带
  • 别用 SELECT * 去“赌”覆盖,它会让优化器直接放弃走索引,尤其当表有大字段(如 TEXT)时,索引体积爆炸,得不偿失

为什么有时候明明建了索引,EXPLAIN 却不显示 Using index

常见原因不是索引没建对,而是查询本身“破坏”了覆盖条件:

  • ORDER BY 字段不在索引中或顺序不匹配:比如索引是 (status, created_at),但查询写 ORDER BY created_at DESC,而索引默认升序,可能导致无法利用索引排序,触发文件排序(Using filesort),进而中断覆盖
  • 隐式类型转换:字段是 VARCHARWHERE 条件却传数字(如 WHERE mobile = 13800138000),MySQL 会强制转类型,导致索引失效
  • 对索引列用了函数或运算:WHERE YEAR(create_time) = 2025WHERE price * 1.1 > 100,索引值被修改,无法直接比对
  • 使用了 OR 且部分分支无索引:哪怕左边字段有索引,右边没有,整个条件大概率走全表扫描

覆盖索引不是万能的,别在这些场景硬上

它省的是 I/O,但代价是索引体积变大、写入变慢、内存占用升高。以下情况要谨慎:

  • 查询字段太多(比如 8 个以上),尤其是含大文本字段——索引可能比数据还大,缓存效率反而下降
  • 写多读少的表:每条 INSERT/UPDATE 都要维护多个覆盖索引,性能损耗明显
  • 高频 LIKE '%keyword' 查询:B+Tree 对前导通配符无能为力,覆盖索引也救不了
  • 需要 GROUP BY + 聚合函数(如 SUM())且分组字段未覆盖:聚合仍需扫描原始行,覆盖索引意义有限

最常被忽略的一点:覆盖索引对 SELECT count(*) 有奇效(InnoDB 可直接扫索引统计),但对 SELECT COUNT(col)col 允许 NULL)则不一定——它得确认该列非空,可能仍需回表校验。

text=ZqhQzanResources