SQL Server中临时表的作用范围

61

我编写了一个存储过程,用于将数据从一个数据库导入并转换到另一个数据库。每个导入将使用单个公司ID,并导入与该公司相关的所有数据。

为了帮助转换步骤,我使用临时表。在脚本审查的过程中,我被告知应该使用表变量而不是临时表。 审阅人员声称,如果我们同时运行两个不同的导入,那么临时表将被共享并破坏导入。


问题:

  • 如果我们同时运行两个不同的导入,临时表会被共享吗?
  • 每次调用EXEC都会创建一个新的作用域吗?

这里是这个脚本的一个虚构示例。

CREATE PROC [dbo].[ImportCompany]
(
    @CompanyId AS INTEGER
)
AS
EXEC [dbo].[ImportAddress] @CompanyId = @CompanyId 
--Import other data

CREATE PROC [dbo].[ImportAddress]
(
    @CompanyId AS INTEGER
)
AS
    CREATE TABLE #Companies (OldAddress NVARCHAR(128), NewAddress NVARCHAR(128))
    INSERT INTO #Companies(OldAddress, NewAddress)
    SELECT
        Address as OldAddress,
        'Transformed ' + Address as NewAddress
    FROM
        [OldDb].[dbo].[Addresses]
    WHERE
        CompanyId = @CompanyId

    --Do stuff with the transformed data

    DROP TABLE #Companies

EXEC [dbo].[ImportCompany] @CompanyId = 12345
4个回答

79
CREATE TABLE 中得知:

本地临时表只在当前会话中可见。

更重要的是:

如果在可以同时由多个用户执行的存储过程或应用程序中创建了本地临时表,则数据库引擎必须能够区分不同用户(应该是会话而不是用户)创建的表。数据库引擎通过在每个本地临时表名称后面内部添加数字后缀来实现此目的。

这正好驳斥了声称临时表将被共享的观点。


此外,你的存储过程末尾无需执行DROP TABLE操作(同样来源):

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


4
“该句子‘可以由多个用户同时执行,数据库引擎必须能够区分不同用户创建的表’很令人困惑!似乎是不同会话中的同一用户共享临时表。但实际上并非如此。” - Alex
@Alex - 我同意这可能有些令人困惑,但不幸的是,这就是微软选择措辞的方式。 - Damien_The_Unbeliever

52

## 用于全局临时表 - 可在不同的导入中使用。

# 用于本地临时表,仅可在当前/内部范围内使用。


3
本地临时表也可以在内部作用域中看到,例如:http://sqlfiddle.com/#!6/d41d8/6725/1 - Andomar

23

一个会话无法看到另一个会话的临时表。因此,不管您使用临时表还是表变量,不同的导入都不会互相影响。

例外情况是以##开头的全局临时表,它们可见于所有连接。


6
我刚刚花了几个小时努力寻找一个临时表在触发器中行为异常的原因。然后我意识到,这个临时表的名称与用于插入触发器所触发数据的存储过程中的临时表名称相同。
现在我意识到这对我来说应该是显而易见的,但这是典型的一种情况,当我们试图弄清楚为什么某些事情不合理时,经常会忽视最明显的原因。
因此,需要记住当一个存储过程调用另一个存储过程或者触发器时,临时表的名称必须在这些之间唯一,以防止产生不良副作用。
此外,即使在内部存储过程中执行以下代码,它也不能像预期的那样工作。因为外部存储过程似乎锁定了临时表名。
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
    DROP TABLE #TempTable

2
我觉得这个答案可能有帮助并与问题相关,但如果您可以改变措辞以更清楚地说明它如何直接影响OP所问的情况,那么它可能会更受欢迎。 - DaveyDaveDave
1
据我所知,如果从不同的进程调用临时表,则只有在使用双重哈希##Table定义它们时才会共享。否则,它们仅对当前进程和由该进程生成的进程可见。请参考https://stackoverflow.com/users/10620912/michael-cooper在此线程中的答案,以获得清晰明了的解释:https://dev59.com/P2Ei5IYBdhLWcg3wueR0。 - Nel Prinsloo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接