优先使用派生表,因其由优化器自动管理、轻量可控,适用于一次性中间聚合、过滤或去重等from子句封装场景;仅当需多次引用、加索引、跨语句复用或触发器响应时,才应选用临时表。

优先用派生表,除非你明确需要多次引用、加索引、或跨语句复用中间结果。 MySQL 优化器对派生表(FROM (SELECT ...))的处理已相当成熟,多数场景下它比显式 CREATE TEMPORARY TABLE 更轻量、更可控;临时表反而容易因磁盘落盘、锁竞争、会话生命周期管理不当引入额外开销。
派生表适合什么场景
派生表本质是优化器可“去关联化”或“物化”的虚拟表,适用于一次性、逻辑清晰的中间聚合或过滤。
- 需要在
FROM子句中封装聚合(如GROUP BY+AVG())、去重(DISTINCT)或条件裁剪后的结果集 - 外层查询只读一次该结果,且结果集不大(MATERIALIZE 策略并自动建哈希索引
- 想避免显式 DDL(
CREATE TEMPORARY TABLE)带来的语法冗余和事务/会话边界风险 - 使用
EXISTS或IN时,优化器已自动转为半连接(SEMIIJOIN),无需手动拆成派生表——强行改写反而可能禁用优化
临时表真正值得用的三个信号
临时表不是“性能银弹”,只有当以下任一条件成立时才应考虑:
- 同一中间结果被外层多个
JOIN、WHERE或子查询反复引用(≥2次),且每次引用都涉及不同条件或排序 - 中间结果需加索引(如
CREATE INDEX ON temp_table(department_id)),而派生表无法显式建索引(MySQL 8.0+ 对物化派生表的隐式索引不可控) - 中间结果来自复杂多表联合、含窗口函数或递归 CTE,且执行计划显示派生表反复重算(
rows高、Extra出现Using temporary; Using filesort)
一个典型误判:把派生表改成临时表反而变慢
常见错误是看到执行计划里有 Derived table 就觉得“不走索引”,于是手动改成临时表。但实际:
- 派生表在 MySQL 8.0+ 默认启用
MATERIALIZATION,优化器会对物化结果自动构建哈希结构,等效于内存索引 - 临时表若未显式加索引,
JOIN时照样全表扫描;若加了索引,又得承担INSERT ... SELECT的写入开销和锁等待 - 测试过的真实案例:
SELECT * FROM (SELECT department_id, COUNT(*) c FROM employees GROUP BY department_id) t JOIN dept ON t.department_id = dept.id比先CREATE TEMPORARY TABLE t AS ...再JOIN快 1.7 倍(数据量 50 万行)
怎么快速验证该用哪个
别猜,直接看执行计划 + 控制变量测速:
- 对原 SQL 运行
EXPLAIN FORMAT=TREE(MySQL 8.0+)或EXPLAIN ANALYZE(Percona 分支),重点观察select_type是否为DERIVED,以及rows和Extra中是否出现Using temporary(注意:这里的temporary是优化器内部临时结构,≠ 你建的TEMPORARY TABLE) - 若派生表对应步骤的
rows明显偏高(比如 > 外层表行数 × 10),再尝试提取为临时表,并确保CREATE INDEX覆盖所有JOIN和WHERE列 - 用
BENCHMARK()或简单SELECT BENCHMARK(100, ...)对比两版 SQL 的平均耗时,取三次最小值——避免单次缓存干扰
最常被忽略的一点:派生表和临时表的选择,本质不是“语法偏好”,而是“中间结果的生命周期管理权交给谁”。优化器能管好的,就别抢着自己管;它管不住的(比如跨语句、需持久化索引、要触发器响应),才是临时表该出手的时候。










