简体   繁体   English

SQL Server中临时表的范围

[英]Scope of temporary tables in SQL Server

I wrote a stored procedure to import and transform data from one database to another. 我编写了一个存储过程,以将数据从一个数据库导入并转换到另一个数据库。 Each import would take a single company ID and import all data related to this company. 每次导入都将使用一个公司ID,并导入与此公司相关的所有数据。

To help with the transformation step I use temporary tables. 为了帮助进行转换,我使用了临时表。 As part of script review, I was told to use table variables rather than temporary tables. 在脚本审查中,有人告诉我使用表变量而不是临时表。 The reviewer claims that if we run two different imports at the same time, the temporary table would be shared and corrupt the import. 审阅者声称,如果我们同时运行两个不同的导入,则临时表将被共享并破坏导入。


Questions: 问题:

  • Is it true that the temporary table would be shared if we run two different imports at the same time? 如果我们同时运行两个不同的导入,是否可以共享临时表?
  • Does each call to EXEC create a new scope? 是否每个对EXEC调用都会创建一个新的作用域?

Here is a contrived example of the script. 这是该脚本的虚构示例。

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

From CREATE TABLE : CREATE TABLE

Local temporary tables are visible only in the current session 本地临时表仅在当前会话中可见

and (more importantly): 和(更重要的是):

If a local temporary table is created in a stored procedure or application that can be executed at the same time by several users, the Database Engine must be able to distinguish the tables created by the different users [sic - almost certainly this should say sessions not users] . 如果在可以由多个用户同时执行的存储过程或应用程序中创建了本地临时表,则数据库引擎必须能够区分由不同用户创建的表[原文-几乎可以肯定的是,会话不是用户] The Database Engine does this by internally appending a numeric suffix to each local temporary table name. 数据库引擎通过在内部将数字后缀附加到每个本地临时表名称来实现此目的。

Which exactly rebuts the point of whoever said that they would be shared. 无论谁说他们将被分享,这都恰恰反驳了这一点。


Also, there's no need to DROP TABLE at the end of your procedure (from same link again): 另外,在过程结束时也无需DROP TABLE (再次从同一链接):

A local temporary table created in a stored procedure is dropped automatically when the stored procedure is finished 存储过程完成后,将自动删除在存储过程中创建的本地临时表

## is used for global temporary tables - will be available to the different imports. ##用于全局临时表-将可用于不同的导入。

# is used for local temporary tables and only available in the current/inner scope. #用于本地临时表,仅在当前/内部范围内可用。

One session cannot see another session's temporary tables. 一个会话无法看到另一会话的临时表。 So different imports will not affect each other, regardless of whether you use temporary tables or table variables. 因此,无论您使用临时表还是表变量,不同的导入都不会互相影响。

The exception is global temporary tables, which start with ## . 全局临时表例外,该临时表以##开头。 Those are visible to all connections. 这些对所有连接都是可见的。

I just spent a few hours struggling to find out why a temporary table used in a trigger behaved strangely. 我只花了几个小时苦苦挣扎,以找出触发器中使用的临时表为何表现异常。 Then I realised that the temporary table had the same name as a temporary table in the stored procedure used to insert the data that fired the trigger. 然后我意识到临时表与存储过程中的临时表同名,该存储过程用于插入触发触发器的数据。 I am now aware that this should have been obvious to me straight away, but it was a typical case of overlooking the most obvious cause when trying to find out why something did not make sense. 我现在知道这对我本来应该是显而易见的,但是这是一个典型的案例,当试图找出为什么没有意义的时候却忽略了最明显的原因。

So it is important to remember that when a stored proc calls another stored proc or fires a trigger, then temp table names have to be unique across these in order to prevent undesired side-effects. 因此,重要的是要记住,当一个存储的proc调用另一个存储的proc或触发一个触发器时,临时表名称必须在所有这些表中都是唯一的,以防止出现不良的副作用。

Furthermore - even when executing the following code in the inner stored proc, it will not function as expected. 此外-即使在内部存储的proc中执行以下代码,它也不会按预期运行。 Since the outer stored proc seems to lock the temp table name. 由于外部存储的proc似乎锁定了临时表的名称。

IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
    DROP TABLE #TempTable

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM