MySQL 8.0已彻底移除查询缓存,存储过程不依赖Query Cache;其性能依赖连接级执行计划复用、InnoDB缓冲池及会话变量,而非独立缓存。

MySQL 执行存储过程时,**不依赖查询缓存(Query Cache),也不为每个存储过程维护独立的“执行缓存”**;它的上下文和缓存行为完全由连接级会话变量、InnoDB 缓冲池及语句编译机制协同决定。
存储过程没有查询缓存参与
MySQL 8.0 已彻底移除 query_cache 相关所有功能,而即使在 5.7 或更早版本中,存储过程内的 SELECT 语句也**默认不会被查询缓存命中**,原因有三:
- 存储过程体中的 SQL 是动态拼接或带变量的,语句文本每次调用都可能不同(比如含
@var),无法满足“完全相同字符串”这一缓存 key 条件 - 存储过程中大量使用会话变量(如
@counter)、临时表或OUT参数,导致结果不可预测,查询缓存主动跳过 - 只要过程内有任何写操作(
INSERT/UPDATE/DELETE),整个连接的查询缓存都会被清空,进一步削弱实用性
真正起作用的是连接级会话变量与缓冲池
存储过程的“状态”实际靠 MySQL 连接自身的会话上下文维持,而非过程私有内存:
-
DECLARE定义的局部变量只在BEGIN...END块内有效,退出即销毁;它们不进缓冲池,也不跨调用保留 -
SET @var = ...创建的会话变量会一直存在,直到该连接断开——这是你在多次CALL间传递中间结果的唯一可靠方式 - 所有数据读取(如
SELECT ... INTO)最终走的是innodb_buffer_pool:热数据页驻留内存,冷数据页按 LRU 淘汰;这个缓存对存储过程完全透明,但影响其实际执行速度
存储过程的“编译缓存”其实是连接级执行计划复用
所谓“存储过程预编译提升性能”,本质是 MySQL 对同一连接内重复调用的存储过程,会复用上一次生成的执行计划(plan),但有严格前提:
- 必须是**同一个数据库连接**;换连接后,哪怕过程名、参数完全一样,也要重新解析+优化
- 执行计划不会长期驻留;如果期间表结构变更(如加索引、改字段)、统计信息更新(
ANALYZE TABLE),旧 plan 可能被丢弃并重建 - 不适用于含动态 SQL 的过程(
PREPARE/EXECUTE):每次EXECUTE都触发新编译,无法复用
容易被忽略的关键点
很多人以为存储过程像函数一样有“内部缓存”,其实它最脆弱的一环恰恰是连接生命周期——一旦应用用了连接池且未开启 sticky session,两次 CALL 很可能落在不同连接上,导致所有会话变量丢失、执行计划重编译、缓冲池预热失效。这时候性能反而比等价的单条 SQL 更差。


















