临时表是否是线程安全的?

时间:2009-01-21 20:54:26

标签: sql-server multithreading temp-tables

我正在使用SQL Server 2000,并且许多存储过程都广泛使用临时表。数据库有很多流量,我担心创建和删除临时表的线程安全性。

假设我有一个存储过程可以创建一些临时表,它甚至可以将临时表连接到其他临时表等。还可以说两个用户同时执行存储过程。

  • 一个用户是否可以运行sp并创建一个名为#temp的临时表,另一个用户运行相同的sp但是因为数据库中已经存在一个名为#temp的表而被停止了? / p>

  • 如果同一个用户在同一个连接上执行两次相同的存储过程怎么样?

  • 是否还有其他可能导致两个用户查询相互干扰的奇怪场景?

9 个答案:

答案 0 :(得分:33)

对于第一种情况,不可能,因为#temp是本地临时表,因此对其他连接不可见(假设您的用户使用单独的数据库连接)。临时表名称别名为生成的随机名称,并在引用本地临时表时引用该名称。

在您的情况下,由于您要在存储过程中创建本地临时表that temp table will be dropped when the scope of the procedure is exited(请参阅“备注部分”)。

对于第二种情况,是的,您将收到此错误,因为该表已经存在,并且该表持续的时间与连接一样长。如果是这种情况,那么我建议您在尝试创建表之前检查表是否存在。

答案 1 :(得分:8)

创建本地范围的临时表(带有一个#),并在其末尾添加一个标识符,使其唯一;多个呼叫者(即使使用相同的登录名)也不应重叠。

(试一试:从两个连接和相同的登录创建相同的临时表。然后查询tempdb.dbo.sysobjects以查看创建的实际表...)

答案 2 :(得分:5)

本地临时表是线程安全的,因为它们只存在于当前上下文中。请不要将上下文与当前连接混淆(来自MSDN:"存储过程中创建的本地临时表会在存储过程完成后自动删除"),相同的连接可以安全地调用两次或多次创建本地临时表的存储过程(如#TMP)。

您可以通过从两个连接执行以下存储过程来测试此行为。这个SP将等待30秒,因此我们可以确保两个线程将同时运行他们自己版本的#TMP表:

CREATE PROCEDURE myProc(@n INT)
AS BEGIN
    RAISERROR('running with (%d)', 0, 1, @n);
    CREATE TABLE #TMP(n INT);
    INSERT #TMP VALUES(@n);
    INSERT #TMP VALUES(@n * 10);
    INSERT #TMP VALUES(@n * 100);
    WAITFOR DELAY '00:00:30';
    SELECT * FROM #TMP;
END;

答案 3 :(得分:4)

简短的回答是:

  

每个查询保证保证临时表的隔离,并且有   没有什么可担心的是线程,锁或   并发访问。

我不确定为什么这里的答案谈论'连接'和线程的重要性,因为这些是编程概念,而查询隔离在数据库级别处理

本地临时对象由SQL Server中的 Session 分隔。如果您有两个并发运行的查询,那么它们是两个完全独立的会话,并且不会相互干扰。登录无关紧要,例如,如果您使用ADO.NET使用单个连接字符串(意味着多个并发查询将使用相同的SQL服务器'登录'),您的查询将全部仍然单独运行会话。连接池也没关系。本地临时对象(表存储过程)完全安全,不被其他会话看到

澄清这是如何运作的;虽然您的代码具有本地临时对象的单个通用名称,但SQL Server会为每个会话的每个对象附加一个唯一的字符串,以使它们分开。您可以通过在SSMS中运行以下内容来查看此内容:

CREATE TABLE #T (Col1 INT)

SELECT * FROM tempdb.sys.tables WHERE [name] LIKE N'#T%';

您将看到名称如下所示的内容:

Ť_______________ 00000000001F

然后,在不关闭该查询选项卡的情况下,打开新的查询选项卡并粘贴到同一查询中并再次运行它。您现在应该看到以下内容:

Ť_______________ 00000000001F

Ť_______________ 000000000020

因此,每次代码引用#T时,SQL Server都会根据会话将其转换为正确的名称。分离都是自动处理的。

答案 4 :(得分:3)

临时表与会话绑定,因此如果不同的用户同时运行您的程序,则没有冲突......

答案 5 :(得分:1)

临时表仅在创建它们的查询或proc的上下文中创建。每个新查询都会在数据库中获取一个没有其他查询临时表的上下文。因此,名称冲突不是问题。

答案 6 :(得分:1)

如果查看temps数据库,可以在那里看到临时表,并且它们具有系统生成的名称。所以除了常规的死锁之外,你应该没问题。

答案 7 :(得分:0)

除非您使用两个符号## temp临时表将是本地的,并且只存在与该用户的本地连接

答案 8 :(得分:0)

首先让我们确保你使用真正的临时表,它们是以#还是##开头?如果您正在动态创建实际表,然后重复删除并重新创建它们,那么并发用户确实会遇到问题。如果要创建全局临时表(以##开头的表),您也可能遇到问题。如果您不想要并发问题,请使用本地临时表(它们以#开头)。在proc结束时显式关闭它们(或者如果你正在谈论长多步触发,它们不再需要它们)并在创建之前检查是否存在(如果是这样的话,则删除它)也是一种很好的做法。 。