SQL Server全局临时存储过程关闭SSMS查询窗口后立即消失求助
首先得明确:你遇到的是SQL Server全局临时存储过程(##前缀)的设计特性——全局临时对象的生命周期和创建它的会话绑定,当创建它的查询窗口关闭(会话终止),SQL Server会自动清理这些对象,这就是为什么你关闭窗口后存储过程就消失了。
针对你这种只读服务器、需要多个子例程的场景,给你几个实用的解决办法:
办法1:每次执行任务前批量重新创建临时存储过程
不用维持多个窗口,把所有子例程的创建语句整合到一个脚本里,每次需要执行分析任务时,先跑一遍这个脚本创建所有全局临时存储过程,再执行调用逻辑。
举个例子,你可以写一个CreateAllTempProcs.sql脚本:
-- 创建主存储过程 CREATE PROCEDURE ##MyProcedure AS BEGIN -- 你的主分析逻辑 EXEC ##MySubProcedure1; EXEC ##MySubProcedure2; END GO -- 创建子例程1 CREATE PROCEDURE ##MySubProcedure1 AS BEGIN -- 子逻辑1 END GO -- 创建子例程2 CREATE PROCEDURE ##MySubProcedure2 AS BEGIN -- 子逻辑2 END GO
每次要跑分析时,先在查询窗口执行这个脚本,然后再调用EXEC ##MyProcedure;。这种方式简单直接,不用维持会话,大不了每次执行前花几秒重新创建一遍,对性能几乎没影响。
办法2:用一个持久会话维持所有临时存储过程
专门开一个查询窗口,执行完所有全局临时存储过程的创建语句后,执行一个无限等待的语句来保持会话活跃,这样其他窗口就能一直调用这些存储过程。
步骤:
- 打开一个新的查询窗口,连接到目标服务器;
- 执行所有
CREATE PROCEDURE ##XXX的语句; - 执行以下语句让会话保持运行:
-- 保持会话活跃,设置一个很长的延迟,比如24小时 WAITFOR DELAY '23:59:59';
你可以最小化这个窗口,只要不关闭它,全局临时存储过程就会一直存在。如果需要更新存储过程的定义,直接在这个窗口重新执行创建语句覆盖即可。
⚠️ 注意:全局临时存储过程是所有会话可见的,所以最好给名称加上唯一标识(比如你的用户名前缀),避免和其他用户的临时对象冲突,比如改成##Elaskanator_MyProcedure。
办法3:将逻辑嵌入查询,避免使用临时存储过程
如果子例程的逻辑不算特别复杂,可以把存储过程里的逻辑直接写成CTE、表值函数或者动态SQL,嵌入到主查询中。虽然牺牲了一点代码复用性,但不用依赖临时对象的生命周期问题。比如把子例程的逻辑封装成表值函数:
CREATE FUNCTION ##MySubFunc1() RETURNS TABLE AS RETURN ( -- 子逻辑的查询语句 SELECT * FROM ReadOnlyTable WHERE Condition = 1 ) GO
然后在主查询中直接调用SELECT * FROM ##MySubFunc1();,同样适用前面的两种办法来维持它的存在。
内容的提问来源于stack exchange,提问作者Elaskanator

