首页/数据/数据库速查/临时表与派生表(FROM 子查询)
SQL 语法52 条

临时表与派生表(FROM 子查询)

临时表用于会话内暂存中间结果;派生表把子查询当作表参与连接;8.0 优化器常把派生表合并展开。

数据库速查数据更新于 2026-10-13

临时表与派生表是什么

临时表(CREATE TEMPORARY TABLE)是会话级的表,用于暂存中间结果,会话结束自动清理。派生表是把子查询写在 FROM 后面当作一张表参与后续查询,它的作用域只在当前语句内。8.0 的优化器默认会尝试把派生表「合并」进外层查询(derived merge),从而让外层条件能下推到底层表;无法合并时会物化成内部临时表,这就是派生表查询突然变慢的常见原因。

基本信息

临时表语法CREATE TEMPORARY TABLE 名 (列定义 ...)
可见范围仅创建它的会话可见,会话结束自动删除
派生表写法FROM (SELECT ...) AS 别名
优化行为derived_merge 开启时优先合并,否则物化为内部临时表
落盘条件物化结果过大超过内存临时表上限时落磁盘

典型使用场景

  • 多步数据处理:把第一步聚合结果放进临时表,后续多轮查询反复使用
  • 大列表过滤:把一批 ID 先写入临时表,再用 JOIN 替代超长 IN 列表
  • 分步排查:拆开复杂查询,逐步把中间结果物化以便对照行数
  • 批量更新前筛选:先把目标主键集合落到临时表,再按集合更新,避免重复扫描
  • 替代复杂派生表:当派生表被反复引用时改用临时表,语义更清晰且只计算一次

两种写法对照

两种写法对照
-- 临时表:会话级,可多次引用,用完显式删除
CREATE TEMPORARY TABLE tmp_top (
  user_id BIGINT PRIMARY KEY, total DECIMAL(14,2)
) ENGINE=InnoDB;
INSERT INTO tmp_top
SELECT user_id, SUM(amount) FROM appdb.orders GROUP BY user_id ORDER BY SUM(amount) DESC LIMIT 100;
SELECT * FROM tmp_top ORDER BY total DESC LIMIT 10;
DROP TEMPORARY TABLE tmp_top;
-- 派生表:只在当前语句内有效
SELECT t.user_id, t.total FROM (
  SELECT user_id, SUM(amount) AS total FROM appdb.orders GROUP BY user_id
) AS t WHERE t.total > 10000;

选择建议

情形建议写法原因
中间结果被多次引用临时表只计算一次,后续直接读
子查询可被外条件下推派生表合并后等价于一次查询,更省
派生表需要聚合且外层条件多改临时表或改写查询合并失败会物化,代价高
需要索引或主键加速临时表派生表无法建索引
只是一次性过滤子查询或 JOIN避免额外的建表与清理开销
临时表与真实表同名时,会话内优先访问临时表:这会制造「数据确实写进去了但别人查不到」的假象。命名统一加 tmp_ 前缀能避免这类混淆。
用 EXPLAIN 观察派生表是否被物化:出现物化相关提示说明未能合并,此时应考虑改写查询或改用临时表,并关注是否落磁盘。

易错点

  • 临时表与真实表同名:会话内优先访问临时表,排查时容易误判数据去向,命名统一加前缀
  • 大派生表被物化并落磁盘:表现为查询突然变慢,用 EXPLAIN 确认是否合并失败后再决定改写方式
  • 临时表忘记 DROP:会话不断开时资源一直占用,长连接池场景下会持续积累
  • 把临时表当成跨会话共享的缓存:它只对创建它的会话可见,其他连接查不到,设计时不要依赖这个前提
  • 在高频查询里反复建临时表:建表与清理本身有开销,简单过滤场景直接用子查询或 JOIN 更划算

数据来源与参考

  • MySQL 8.0 Reference Manual: CREATE TEMPORARY TABLE Statement

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌