mysql 8.0 已移除查询缓存,其与索引无协同关系;真正影响性能的是优化器选择索引生成执行计划,以及和索引紧密配合的 innodb buffer pool 缓存数据页和索引页。

MySQL执行SQL时,查询缓存(Query Cache)和索引不是协同工作的关系
MySQL 8.0 已彻底移除 query_cache_type 和相关机制,5.7 及更早版本中它也仅对完全一致的 SELECT 文本生效,且一旦表有写入(INSERT/UPDATE/DELETE),对应所有缓存就会被清空。这意味着:索引用于加速数据定位,而查询缓存只是“结果字符串”的键值对缓存——两者在执行流程中无逻辑耦合,也不共享结构或状态。
常见误解是“用了索引,缓存命中率就高”,其实完全无关:即使全表扫描的 SQL,只要文本没变、表没更新,也能命中查询缓存;反之,哪怕走了完美索引,只要 SQL 多了个空格或参数不同,就完全不命中。
真正影响执行效率的是:优化器如何用索引生成执行计划
MySQL 在解析 SQL 后,会由优化器评估可用索引(基于 WHERE、ORDER BY、GROUP BY 等子句),选择成本最低的访问路径。这个过程与缓存无关,但直接决定是否走索引、走哪个索引、是否用到联合索引的最左前缀。
-
EXPLAIN输出中的type字段是关键:从const→ref→range→index→ALL,性能通常递减 - 联合索引
(a,b,c)能支持WHERE a=1 AND b=2,但不支持WHERE b=2单独查询(除非是覆盖索引且满足其他条件) -
ORDER BY若无法利用索引排序,会触发Using filesort,这是性能热点之一
执行流程中真正起作用的缓存其实是 InnoDB Buffer Pool
这才是和索引紧密配合的缓存层。InnoDB 不缓存查询结果,而是缓存数据页(.ibd 文件中的 page)和索引页。当 SQL 使用索引定位记录时,实际读取的是 Buffer Pool 中的内存页;若未命中,才从磁盘加载并可能淘汰旧页。
关键点:
- Buffer Pool 大小由
innodb_buffer_pool_size控制,应设为物理内存的 50%–75%,太小会导致频繁磁盘 I/O - 索引本身也被加载进 Buffer Pool,所以高频访问的索引节点会常驻内存,加快后续查找
-
SHOW ENGINE INNODB STATUS中的Buffer pool hit rate建议保持在 99%+,低于 95% 就该排查是否 Buffer Pool 不足或存在低效全扫
为什么你看到的“缓存生效”往往不是 Query Cache
很多线上环境显示“查询变快了”,其实主因是 Buffer Pool 预热后数据页已在内存,或者操作系统页缓存(page cache)保留了刚读过的磁盘块。这些都无需配置、自动生效,但和 SQL 文本是否重复毫无关系。
容易踩的坑:
- 在 5.7 上还开着
query_cache_type = 1,反而因维护缓存锁导致并发写入性能下降 - 误以为
SELECT COUNT(*) FROM t走了索引就一定快——实际上如果没合适索引,InnoDB 仍需遍历聚簇索引,且 Buffer Pool 若未预热,首次执行依然很慢 - 用
SQL_NO_CACHE测试性能,却忽略了 Buffer Pool 还是热的,结果误判索引无效
真实调优必须分层验证:先看 EXPLAIN 是否走了预期索引,再看 SHOW PROFILE 或 Performance Schema 判断耗时是否卡在 sending data(说明数据量大或未走索引),最后确认 Buffer Pool 命中率和 I/O 状态。把“缓存”想成单一开关,是多数人起步时最深的误区。











