MySQL 8.0 彻底移除查询缓存,query_cache_type 已删除;重复 SQL 必须重解析执行,预处理语句和 InnoDB 缓冲池才是实际缓存机制;应用层应主动用 Redis 等实现可控缓存。

MySQL 8.0 默认不启用查询缓存,query_cache_type 已被移除
MySQL 5.7 及更早版本支持的查询缓存(Query Cache)在 8.0 中彻底删除。这意味着无论你执行多少次相同的 SELECT 语句,MySQL 都不会从内存中直接返回结果——它必须走完整的解析、优化、执行流程。如果你还在用 8.0+ 并期待“SQL 缓存自动生效”,那这个预期本身就是错的。
常见误判现象:SHOW VARIABLES LIKE 'query_cache%' 在 8.0 中查不到任何变量;配置文件里写了 query_cache_type=1 会启动失败或静默忽略。
每次执行 SQL 确实都会重新解析,但有预处理语句(PREPARE)和连接级缓存可缓解
MySQL 对普通文本协议(text protocol)的 SQL,每次请求都做词法分析 → 语法分析 → 语义检查 → 生成执行计划。即使语句完全相同,只要没复用预处理对象,就无法跳过解析阶段。
-
PREPARE stmt FROM 'SELECT * FROM users WHERE id = ?'后,多次EXECUTE stmt USING @id可复用解析结果和执行计划 - 客户端驱动(如 Python 的
pymysql、Java 的PreparedStatement)默认启用预处理,但需确认是否实际走 binary protocol - 注意:表结构变更(如加索引、改字段类型)会导致已缓存的执行计划失效,下次仍需重编译
真正起效的“缓存”在服务端是 InnoDB 缓冲池,不是 SQL 层
所谓“重复查询变快”,绝大多数情况是因为第二次执行时所需的数据页已在 innodb_buffer_pool 中,避免了磁盘 I/O。这和 SQL 文本是否相同无关,只和访问的数据块有关。
验证方式:
- 第一次执行后查
SHOW STATUS LIKE 'Innodb_buffer_pool_read_requests'和Innodb_buffer_pool_reads,差值越大说明缓存命中越差 - 执行
SELECT COUNT(*) FROM information_schema.INNODB_BUFFER_PAGE可粗略看缓冲池使用量 - 如果
innodb_buffer_pool_size远小于数据总大小,反复执行同一条 SQL 依然可能频繁换页、表现不稳定
应用层该怎么做:别依赖 MySQL 自动缓存,自己控制粒度
想避免重复解析 + 执行开销,不能靠等 MySQL “聪明起来”。得明确谁负责缓存、缓存什么、何时失效。
- 高频读、低频写的数据(如配置表、省份列表),用 Redis 缓存完整结果集,键名可带版本号或
TTL - 用 ORM 时慎用动态拼接 SQL,优先走参数化查询 + 预编译路径(如 Django 的
raw()不如filter(id__in=[...])可优化) - 监控慢日志里反复出现的相同
SQL_TEXT,不是加索引就能解决——要判断是否该由应用兜底缓存
SELECT query_time, lock_time, rows_sent, sql_text FROM mysql.slow_log WHERE sql_text LIKE 'SELECT % FROM orders WHERE user_id = %' ORDER BY start_time DESC LIMIT 5;
复杂点往往不在 SQL 是否被“缓存”,而在于你是否清楚当前这行语句,到底是在和网络、解析器、锁管理器、还是磁盘打交道。










