数据量超1000行必须用#TempTable而非@Table;@Table仅适用于函数内小数据量场景,而#TempTable支持跨批访问、统计信息更新及索引优化,性能差异可达百倍。

数据量超过1000行时必须用#TempTable
优化器对@Table固定按5行估算,哪怕你插入5000行,执行计划仍可能选嵌套循环连接、跳过哈希匹配,WHERE条件走全表扫描,JOIN时内存溢出到tempdb。实测插入10000行:@t耗时16806ms,#t仅76ms;用SELECT ... INTO #t更只要30ms。
以下情况直接排除@Table:
- 需要多次
JOIN/GROUP BY/ORDER BY - 中间结果要被多个独立语句复用(比如先聚合、再过滤、再关联主表)
- 后续操作依赖统计信息(如
UPDATE STATISTICS #tmp可手动触发)
嵌套存储过程里只能用#TempTable
@Table作用域严格限定在当前批处理(batch),EXEC sp_executesql或内层存储过程根本看不到外层声明的@Table,会报“对象名无效”。而#TempTable支持跨批、跨层级访问——外层建#temp,内层能UPDATE、SELECT、甚至加索引。
全局临时表##GlobalTemp虽也跨会话,但高并发下极易数据污染,99%场景该用#LocalTemp。
函数里没得选,只能用@Table
SQL Server函数禁止创建或引用#TempTable,语法直接报错。但要注意:@Table在函数中无法运行UPDATE STATISTICS,优化器完全无视实际行数,复杂逻辑下性能可能比预期差几倍。
字段类型别乱用SQL_VARIANT或自定义类型,跨函数时容易隐式转换失败。
内存优化表变量是小数据量的进阶选项
如果你用的是 SQL Server 2014+ 或 Azure SQL,且数据量≤100行、需高频读写、又想避开tempdb争用,可以考虑内存优化表变量:
- 必须分两步:先
CREATE TYPE my_type AS TABLE,再DECLARE @mytablevariable my_type - 必须带索引(哈希或非聚集),哈希索引桶数建议设为预期唯一键数的1–2倍
- 不写日志、不占事务空间、无I/O,但部署时需提前建好类型,不能在运行时动态创建
真正容易被忽略的点是:字段名含空格时,SELECT * INTO #tmp会因解析失败中断,必须显式写SELECT [user name] AS [user name];另外,存储过程异常退出时#TempTable虽会自动清理,但反复调试时漏掉DROP TABLE IF EXISTS #tmp,下次执行就卡在There is already an object named '#tmp' in the database。











