在TSQL中的嵌套sp调用中创建的临时表的范围和寿命

时间:2018-09-19 10:14:37

标签: sql-server sql-server-2012 scope temp-tables lifetime

我用临时表修改了一些sp,以消除每个sp中的数十个declare @vars。单独运行,它们似乎运行良好,直到我编写了一个测试用例脚本,然后遍历生产系统中的实时记录以测试这些未发布的新sps(ATM,我想不出更好的方法来遍历参数集来对其进行测试。没有光标的地方。请尽量不要在此处重点关注光标的使用)。重复exec期间我得到了不同的结果。 例如

-- sub_sp2: 
-- sub_task2
select top 1 col1, col2, .... col30 
       into #temp_sub_sp2 
from tb1
left join tbl_ext1 
left join tbl_ext2
left join tbl_ext3
left join tbl_ext....
where cond1 = true

if @@row_count < 0 
    print cond1=true do A thing
else 
    print cond1=false do B thing

-- sp1: 
-- this is a master sp with a couple of sub tasks written in sub_sps.

exec sub_sp2 param1,...., @task2_result output
exec sub_sp3 param1,...., @task3_result output
exec sub_sp4 param1,...., @task4_result output
-- do sth with @result1

-- test script:
-- a test script to call sp1 repeatedly with 
-- different parameters from production system to check result.
declare cur1 ...
   for select colx from prd_mach_status
open cur1
fetch next from cur1 into @param1
...
while ...
    exec sp1 @param1

结果就像

| param1 | print          |
| value1   | cond1 = 1 do A |
| value1   | cond1 = 0 do B |
| value2   | cond1 = 0 do B |
| value1   | cond1 = 0 do B |

实时数据各不相同,但始终遵循相同的模式。在第一个cond1为true之后,以下exec将全部导致cond1 =0。即使cond1为true。

在第一个成功的select into之后,显然select into失败了。 SP2或SP1终止后,临时表不会释放。

在此,本地#temp_sp2是在sp2的范围内而不是从外部范围创建的,一旦调用返回,创建范围将不再有效,但表将不被释放。感觉到后者对同一sp的调用与先前的调用具有相同的作用域。

我已经知道以下内容:

  • 临时表只是在tempdb中带有奇特名称的别名表。
  • 范围的概念定义了它们的可见性
  • 会话是按连接分开的顶级范围。

我的问题是关于他们的寿命。通常,一旦创建了对象,它就绑定到本地函数作用域,一旦作用域消失,该对象就会被GCed。在此嵌套sp中创建的本地临时表显然不遵循此要求。

这里的陷阱是什么,当对范围的常规理解不适用(例如python)时,应如何使用它。

Scope of temporary tables in SQL Server的答案实际上与此矛盾。

  

此外,在过程结束时也无需删除表(从   再次相同的链接):

     
    

存储过程完成后,将自动删除在存储过程中创建的本地临时表

  

从@ Panagiotis-Kanavos的评论中,我似乎了解到temp表(确切地说是它们的奇特别名映射,不一定是真实表)具有可见性/创建范围,但直到会话结束。这可以解释事情,但与建议问题的答案中的先前陈述相矛盾。

  

范围和生命周期并不真正适用。 SQL不是C#。 #somename是在执行create table语句时创建的真实表,并且只要会话/连接处于打开状态就存在。

现在我更困惑了...

1 个答案:

答案 0 :(得分:0)

根据我的经验,#temp_table的范围在当前会话中。因此,只要单独执行这些SP,就可以了。但是,如果将SP作为同一脚本的一部分执行,则#temp_tables可能在脚本内具有作用域。

我的建议是在SP中创建 DROP 。这是每次#temp_table是由同一脚本中的单独SP创建的,每次都会重新创建。