全局临时表名必须以##开头且长度不超过116字符,系统自动追加后缀;建表需用create table ##xxx;不可在函数中使用;生命周期依赖引用计数;高并发下注意tempdb争用。

全局临时表名必须以 ## 开头,且不能超过 116 字符
SQL Server 对全局临时表的命名有硬性限制:## 是强制前缀,后面接的表名长度不能超过 116 字符(因为系统会自动追加数字后缀用于区分并发会话)。比如 ##OrderSummary2024Q3 合法,但 ##ThisIsAnExtremelyLongGlobalTempTableNameThatExceedsOneHundredSixteenCharacters 会报错 Identifier name is too long。
常见错误现象是:建表语句执行成功,但后续 SELECT 或 INSERT 报错 Invalid object name '##xxx'——往往是因为名字超长导致系统截断或生成冲突名。
- 建表时直接用
CREATE TABLE ##MyGlobalTemp (id INT, name VARCHAR(50)) - 避免在名字里拼接动态时间戳(如
##Report_20260929_123456),优先用固定、简洁的命名 - 若需多会话协同写入,务必确保所有调用方使用完全相同的表名(大小写敏感取决于实例排序规则)
全局临时表在最后一个引用会话断开后才销毁
和本地临时表(#)不同,## 表的生命周期不绑定于单个存储过程或会话,而是依赖“引用计数”:只要还有一个活动连接正在访问它,表就存在。这意味着:
- 如果存储过程中创建了
##TempData,然后该存储过程结束,但调用它的客户端连接仍开着,表不会消失 - 另一个连接执行
SELECT * FROM ##TempData成功,说明表还在;但如果此时原连接已断开、且无其他连接在用,下次再查就会报Invalid object name - 显式执行
DROP TABLE ##TempData是安全的,但仅对当前连接有效;若其他连接正持有锁(比如事务中用了WITH (XLOCK)),则会阻塞直到锁释放
不能在函数中创建或引用全局临时表
SQL Server 明确禁止在用户定义函数(UDF)中使用 CREATE TABLE ##xxx 或 SELECT ... FROM ##xxx,会直接报错 Invalid use of a side-effecting operator 'CREATE TABLE' within a function 或 Invalid object name '##xxx'。
这是因为函数要求确定性与无副作用,而全局临时表跨会话、可被并发修改,破坏隔离性。如果你看到类似需求,实际应改为:
- 改用表值参数(
TABLE类型变量)传入数据 - 把逻辑移到存储过程中处理,函数只做纯计算
- 用持久表 + 时间戳/会话ID 字段模拟“临时”语义(需自行清理)
性能与并发要注意 tempdb 争用
所有全局临时表物理上都建在 tempdb,高并发场景下容易成为瓶颈。特别是当多个存储过程频繁创建/删除同名 ## 表时,tempdb 的元数据锁(SCH_M)可能排队。
实测建议:
- 避免在循环内反复
DROP TABLE ##X; CREATE TABLE ##X;,尽量复用已有表结构 - 如果只是临时中转数据,优先考虑本地临时表(
#)或表变量(@tableVar),它们开销更低 - 必要时给
##表加索引:CREATE INDEX IX_##TempData_Id ON ##TempData(id),但注意索引也存于tempdb
真正需要全局临时表的场景其实很少——多数时候你以为需要共享,其实只是没设计好调用链路。先确认是否真要跨连接可见,否则默认用 # 更稳。











