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

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

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

  • 一个用户是否可以运行sp,并创build一个名为#temp的临时表,而另一个用户运行同一个sp,但由于名为#temp的表已经存在于数据库中而停止运行?

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

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

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

在你的情况下,因为你正在存储过程中创build一个本地临时表,所以在退出过程的范围时 , 这个临时表将被删除 (见“备注部分”)。

对于第二种情况,是的,你会得到这个错误,因为这个表已经存在了,并且这个表持续的时间和连接一样长。 如果是这种情况,那么我build议您在尝试创build表之前检查表的存在。

局部范围的临时表(带有一个#)在它们的末尾用一个标识符来创build,这使得它们是唯一的; 多个呼叫者(即使具有相同的login)也不应该重叠。

(尝试:从两个连接和相同的login创build相同的临时表,然后查询tempdb.dbo.sysobjects以查看创build的实际表…)

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

您可以通过从两个连接执行以下存储过程来testing此行为。 这个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; 

临时表与会话绑定,所以如果不同的用户同时运行你的程序,就不会有冲突。

简短的回答是:

临时表的隔离保证每个查询 ,并且不必担心线程,锁或并发访问。

我不确定为什么答案在这里讨论“连接”和线程的意义,因为这些是编程概念,而查询隔离是在数据库级别处理的

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

澄清这是如何工作的; 而您的代码具有本地临时对象的单一通用名称,则SQL Server会在每个会话中为每个对象附加一个唯一string,以使它们保持独立。 您可以通过在SSMS中运行以下内容来看到这一点:

 CREATE TABLE #T (Col1 INT) SELECT * FROM tempdb.sys.tables WHERE [name] LIKE N'#T%'; 

你会看到这样的名字如下:

T_______________00000000001F

然后,在不closures该查询选项卡的情况下,打开一个新的查询选项卡并粘贴相同的查询并再次运行。 您现在应该看到如下所示的内容:

T_______________00000000001F

T_______________000000000020

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

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

如果您查看临时数据库,您可以在那里看到临时表,并且它们具有系统生成的名称。 所以除了常规的僵局,你应该可以。

除非使用两个磅符号## temp,临时表将是本地的,只存在于本地连接到用户

首先让我们确保你正在使用真正的临时表,他们开始用#或##? 如果您正在创build实际表格,然后重复删除并重新创build表格,则确实会遇到并发用户问题。 如果您正在创build全局临时表(以##开头),您也可能遇到问题。 如果不希望并发性问题使用本地临时表(它们以#开头)。 在proc结束时明确地closures它们(或者如果你正在使用多步骤的proc时,proc不再需要它们),并且在创build之前检查是否存在(如果是的话) 。