MySQL 8.0 已彻底移除查询缓存(query_cache),相关变量如 query_cache_type、query_cache_size 均被删除,启动时若配置会报错;替代方案是应用层缓存(如 Redis)或优化 InnoDB 缓冲池等机制。

MySQL 查询缓存(query_cache)已彻底移除,别再配置它
MySQL 8.0 起,query_cache_type、query_cache_size 等所有查询缓存相关变量已被删除。如果你在 8.0+ 版本中仍尝试设置它们,启动会失败并报错:Unknown system variable 'query_cache_type'。这不是配置没生效,是代码里真没了。
原因很直接:查询缓存的维护开销远超收益——只要表有任意写入(INSERT/UPDATE/DELETE),该表所有缓存结果立即失效;高并发写场景下,缓存命中率趋近于零,反而拖慢全局锁争用。
- 5.7 是最后一个支持它的版本,但默认已禁用(
query_cache_type = 0) - 如果你从 5.6 升级到 8.0,务必检查 my.cnf 中是否残留
query_cache_*配置项 - 替代方案不是“换一个缓存”,而是转向更可控的层级:应用层缓存(如 Redis)或 MySQL 自身的缓冲机制
InnoDB 缓冲池(innodb_buffer_pool_size)是性能关键开关
这是 MySQL 中影响查询性能最显著的单个配置项。它决定 InnoDB 能把多少数据和索引页常驻内存,避免频繁磁盘 I/O。若设置过小,即使 SQL 写得再好,也会被大量 Buffer pool hit rate 低于 95% 的现象拖垮。
实操建议:
- 专用数据库服务器上,可设为物理内存的 70%–80%,例如 32GB 内存 →
innodb_buffer_pool_size = 24G - 切勿设为超过可用内存,否则触发系统 swap,性能断崖式下跌
- 大于 1GB 时,启用多实例以减少内部锁竞争:
innodb_buffer_pool_instances = 8 - 监控是否有效:执行
SHOW ENGINE INNODB STATUS\G,关注Buffer pool hit rate和Pages free比例
覆盖索引 + 延迟关联能绕过回表,显著减少随机 I/O
当 SELECT * 或非索引字段出现在查询中,InnoDB 常需先走二级索引定位主键,再回聚簇索引查完整行(即“回表”)。这会产生大量随机读,尤其在大表上非常慢。
优化路径有两个方向:
-
覆盖索引:确保
WHERE条件和SELECT字段全部落在同一索引中。例如:SELECT user_id, name FROM users WHERE status = 1,可建联合索引INDEX idx_status_name (status, name),避免回表 -
延迟关联(Deferred Join):先用覆盖索引快速拿到主键,再用主键
IN关联原表。例如:SELECT u.* FROM users u INNER JOIN (SELECT id FROM users WHERE status = 1 LIMIT 100) t ON u.id = t.id;
这比直接SELECT * FROM users WHERE status = 1 LIMIT 100在某些场景下快数倍 - 注意:覆盖索引会增大索引体积,写入开销略升;延迟关联在
LIMIT很大或子查询结果集膨胀时可能失效
ORDER BY + LIMIT 组合容易误用索引,必须看执行计划
很多人以为加了 ORDER BY created_at DESC LIMIT 20 就一定走 created_at 索引,其实不然。如果 WHERE 条件无法过滤出少量记录,MySQL 可能选择全表扫描后排序,而不是走索引再回表取数据。
关键判断依据是 EXPLAIN 输出中的 type 和 Extra 字段:
-
type = index或range是理想情况;type = ALL表示全表扫描 -
Extra出现Using filesort不一定坏,但若同时rows数值极大,说明排序成本高 - 常见陷阱:对
status = 1 AND created_at > '2024-01-01'排序时,只建(created_at)索引无效,应建(status, created_at)联合索引,且字段顺序必须匹配 WHERE 中的等值条件优先
复杂排序逻辑(如多字段、表达式、函数)几乎无法走索引,这时候考虑物化中间结果或应用层排序更实际。











