with在存储过程中不一定被物化,mysql 8.0+默认内联展开cte,仅当同一cte被引用两次及以上或显式使用materialized提示(8.0.31+)时才可能物化,但物化有i/o和内存开销,未必提速;性能提升需同时满足:中间结果多次引用、数据量适中、索引有效、执行计划确为物化且实测耗时下降。

不一定提升性能,甚至可能变慢——关键看是否被多次引用、是否触发物化、以及MySQL优化器的实际决策。
WITH在存储过程中是否会被物化
MySQL 8.0+ 中,WITH 子句默认采用「内联展开」策略:优化器会把CTE直接替换成子查询,不生成临时结果。这意味着:
- 如果CTE只被引用一次(比如只在主
SELECT中用了一次),WITH和等价的嵌套子查询性能几乎无差别; - 只有当同一个CTE被引用两次及以上(例如出现在
JOIN两侧、或UNION ALL的多个分支中),优化器才可能自动物化它到临时表; - 手动加
MATERIALIZED提示(如WITH mycte AS MATERIALIZED (...) ...)可强制物化,但需MySQL 8.0.31+,且物化本身有I/O和内存开销,未必总是更快。
存储过程里用WITH的常见性能陷阱
在CREATE PROCEDURE中写WITH,容易忽略执行上下文变化带来的影响:
一款AI开发辅助工具,主要用于从 AI 编程会话日志(Clawdbot、Claude Code、Codex)中提取对话记录。该功能用于在用户要求导出提示词历史、会话日志或 `.jsonl` 格式的会话文件时使用,适合需要提升相关任务效率的用户。
- 参数未绑定到CTE内部:若CTE里用了存储过程变量(如
WHERE col = @p_id),而该变量在CTE执行时还未赋值,会导致空结果或全表扫描; - 预编译失效:存储过程中的
WITH语句无法像普通查询一样被服务端缓存执行计划,每次调用都可能重新解析+优化; - 递归CTE无深度限制:在存储过程中用
WITH RECURSIVE时,若没设MAX_RECURSION_DEPTH(通过SET SESSION cte_max_recursion_depth = 100),可能因数据异常导致栈溢出或超时。
什么情况下WITH在存储过程中真能提速
仅当满足以下全部条件时,才较大概率获得性能收益:
- 同一中间结果被至少两次引用(例如:先查出活跃用户列表,再分别用于统计和导出);
- 该中间结果数据量适中(几万行以内),物化成本低于重复扫描原表的代价;
- 原表上对应字段有高效索引,且CTE里的过滤条件能充分利用(否则物化后仍是大表);
- 你显式使用了
MATERIALIZED并验证执行计划中出现了Using temporary且实际耗时下降(用EXPLAIN FORMAT=TREE或profiling对比)。
真正影响性能的从来不是“用了WITH”,而是“是否减少了重复计算”和“优化器有没有按你预期走物化路径”。别假设它自动加速——先看EXPLAIN,再测真实数据集,否则很容易把可读性优化做成性能负优化。










