表变量在高并发下性能更优:不触发重编译、无统计信息抖动、作用域隔离强、物理开销低;但仅适用于≤100行、单次读写、无join场景,否则反成性能黑洞。

表变量不触发重编译,临时表会
存储过程里每执行一次 SELECT INTO #t 或 CREATE TABLE #t,SQL Server 都要生成新执行计划、写入系统元数据、更新 tempdb 统计信息——这在高并发下会争抢 tempdb 的 sysobjects 和 sysindexes 页锁。而表变量 @t 声明后不参与计划缓存管理,INSERT INTO @t SELECT 不会导致整个存储过程重编译。
表变量无统计信息,反而减少计划抖动
高并发场景下,不同会话插入的临时表数据量差异大,但 SQL Server 对 #t 自动生成的统计信息可能滞后或不准,导致后续语句(如 JOIN)反复生成次优计划;而表变量恒按“1 行”估算,虽然不精准,却让执行计划高度稳定——尤其当数据量始终 ≤ 100 行时,这种“固定误判”比“动态误判”更可控。
表变量作用域隔离更彻底
局部临时表 #t 在会话级可见,若存储过程中嵌套调用其他过程,或使用了动态 SQL,#t 名称可能被意外覆盖或冲突;而 @t 严格绑定到声明它的批处理块内,连 EXEC sp_executesql 都无法访问它。高并发时这种强隔离能避免跨请求的数据污染和锁等待。
临时表的物理开销在高并发下被放大
每次创建 #t 都涉及 tempdb 的页分配、IAM 更新、事务日志写入;而表变量初始分配在内存,仅当数据溢出才落盘——且落盘时也走轻量级分配路径,不参与完整事务日志记录。实测中,1000 并发下连续创建/销毁 #t 的 WRITELOG 等待常占总耗时 40% 以上,@t 则几乎无此开销。
真正容易被忽略的是:表变量的“优势”只在 ≤ 100 行、单次读写、无 JOIN 场景下成立;一旦数据量浮动大或需多次关联,它反而是性能黑洞——此时不是并发问题,是执行计划误判本身被放大了。










