绝大多数场景该用#temp而非@table或##temp;数据量>1000行或需多次join/order by/group by时必须用#temp,≤100行且单语句使用可选@table,函数中强制用@table但无统计信息,##temp因全局可见易致并发脏读,应避免。

直接说结论:绝大多数场景该用 #temp,而不是 @table 或 ##temp;用错类型轻则性能暴跌,重则并发读到别人的数据。
SQL Server 里该选 #temp 还是 @table?
看数据量和后续操作复杂度。优化器对 @table 固定按 5 行估算,插了 5000 行也照旧——JOIN 可能选嵌套循环而非哈希连接,WHERE 条件走全表扫描,内存溢出到 tempdb。
- 数据量 > 1000 行,或要被多次
JOIN/ORDER BY/GROUP BY,必须用#temp - ≤ 100 行且只在单个语句里用(比如简单过滤后直接返回),可选
@table - 函数里只能用
@table,但无法UPDATE STATISTICS,也不能建非主键索引 -
#temp支持CREATE CLUSTERED INDEX,@table不支持ALTER TABLE或显式索引
为什么不能随便用 ##temp?
##temp 是全局的,所有会话都能看到。高并发下 A 用户刚写进 ##tmp_result 的中间值,B 用户下一秒就可能读到,甚至覆盖——报表调度、API 批量调用时极易脏读或主键冲突。
- 本地临时表
#temp会话级隔离,SQL Server 断开连接时自动删,但异常退出时未必立刻释放 - 务必在开头加
DROP TABLE IF EXISTS #tmp_result,否则重试执行直接报错There is already an object named '#tmp_result' in the database - 别依赖“自动清理”,尤其调试阶段反复执行,
DROP是安全底线
MySQL 和 PostgreSQL 怎么写才不翻车?
它们根本不认 # 语法,硬写会建出永久表或报错。
- MySQL 必须写
CREATE TEMPORARY TABLE tmp_calc,漏掉TEMPORARY关键字就真建到磁盘上,第二次执行报Table 'tmp_calc' already exists - MySQL 不支持
SELECT INTO,只能先CREATE再INSERT SELECT;含TEXT/BLOB字段会强制退化为磁盘表,拖慢性能 - PostgreSQL 必须加
ON COMMIT DROP,只写CREATE TEMP TABLE t1会让表活到会话结束——Web 长连接复用会话时,第二次调用直接卡在relation "t1" already exists - PostgreSQL 上
TRUNCATE对临时表无效,ON COMMIT DROP已接管生命周期
字段名带空格或 NULL 怎么处理?
字段名含空格、连字符或保留字时,SELECT INTO #tmp FROM (...) t 会解析失败;NULL 值参与 JOIN 或 WHERE 容易导致结果意外为空。
- 显式用方括号包裹:
SELECT [user name] AS [user name] INTO #tmp FROM ... - 避免用
SELECT INTO自动推导结构,改用CREATE TABLE #tmp (...)显式定义列和 NULL 属性 - 插入前用
ISNULL()或COALESCE()处理 NULL,尤其当后续要JOIN或GROUP BY时 - 字段类型别用
SQL_VARIANT或自定义类型,跨批或函数调用时容易隐式转换失败
真正容易被忽略的不是语法,而是统计信息——#temp 插完数据后不手动跑 UPDATE STATISTICS #tmp,首次查询仍可能按空表估算,执行计划就废了。











