MySQL 5.7 中 query_cache 已弃用,SQL_NO_CACHE 不仅无效,还可能干扰执行计划——别再用它了。应聚焦 InnoDB Buffer Pool 命中率与索引优化,而非查询缓存。

MySQL 5.7 中 query_cache 已弃用,SQL_NO_CACHE 不仅无效,还可能干扰执行计划——别再用它了。
为什么 SQL_NO_CACHE 在 MySQL 5.7 里基本没用
MySQL 5.7 默认关闭查询缓存(query_cache_type = OFF),即使你手动设为 ON,SQL_NO_CACHE 也只在极少数场景下起作用:必须同时满足 query_cache_type=1、SQL 完全静态(无函数、无变量、无注释差异)、且表未被任何写操作触碰过。现实中几乎不存在这样的“干净”查询。
更关键的是:SQL_NO_CACHE 会强制跳过查询缓存路径,但不会跳过语法解析、权限检查、执行计划生成等开销——它不加速查询,只让缓存逻辑绕道,反而可能掩盖真实瓶颈。
- 执行
SELECT SQL_NO_CACHE * FROM orders WHERE id = 123;和SELECT * FROM orders WHERE id = 123;在 5.7+ 下性能差异通常可忽略,因为缓存本就大概率没生效 - 若你发现加了
SQL_NO_CACHE后查询变慢,大概率是执行计划被重算(比如因隐式类型转换或统计信息过期) -
SHOW STATUS LIKE 'Qcache%'显示Qcache_hits = 0?不是因为你用了SQL_NO_CACHE,而是缓存根本没启用或压根没命中
查清现状:先确认 query_cache 是否真在工作
别凭印象判断。运行这两条命令:
SELECT VERSION();
如果输出是 5.7.x 或更高,直接跳过所有 query_cache_* 配置项。
SHOW VARIABLES LIKE 'query_cache%';
重点看三行:
-
query_cache_type是OFF、0或DEMAND→ 缓存已停用,SQL_NO_CACHE无意义 -
query_cache_size是0→ 即使 type=ON,也没空间存缓存 -
have_query_cache是YES≠ 已启用,它只表示编译时支持该功能
若以上任意一项表明缓存未启用,继续调 SQL_NO_CACHE 就像给熄火的车踩空油门。
真正该盯的指标:InnoDB Buffer Pool 命中率
MySQL 5.7 的实际缓存主力是 InnoDB 缓冲池,不是 query_cache。它的“命中率”才决定磁盘 I/O 多少。
查法必须用:
SHOW ENGINE INNODB STATUS\G
在输出里找这一行:
Buffer pool hit rate 987 / 1000注意:这不是百分比,987 表示 98.7%,低于 900(即 90%)才需干预。
- 命中率低 ≠ 要调大
innodb_buffer_pool_size,先看SHOW ENGINE INNODB STATUS里Free buffers是否长期为 0;如果是,说明池子够用,问题在 SQL 扫描太宽(如没索引的WHERE) - 若
Pages read ahead高,说明预读机制频繁触发,往往意味着范围查询没走索引 -
SQL_NO_CACHE对 Buffer Pool 命中率完全无影响——它缓存的是数据页,不是结果集
复杂查询慢,第一反应不该是缓存,而是 EXPLAIN
所谓“缓存命中率低”,本质常是查询太慢、跑不完,缓存根本来不及生效。典型表现:
-
EXPLAIN输出中key列为NULL,type是ALL或index - 多表 JOIN 时,
rows列数值爆炸(比如从 1 万跳到 100 万) -
Extra出现Using filesort或Using temporary
这时候加 SQL_NO_CACHE 不解决任何问题。该做的是:
- 确保
JOIN字段类型严格一致(BIGINT对BIGINT,不能INT对BIGINT) - 把
WHERE条件字段放进联合索引,顺序按选择性从高到低(如(status, created_at)而非反过来) - 把
WHERE DATE(created_at) = '2024-01-01'改成created_at >= '2024-01-01' AND created_at
缓存只是锦上添花,索引和执行计划才是雪中送炭。5.7 之后,SQL_NO_CACHE 这个开关,建议从你的代码模板和运维脚本里彻底删掉。


















