Jul*_*iet 43 sql-server multithreading temp-tables
我正在使用SQL Server 2000,并且许多存储过程都广泛使用临时表.数据库有很多流量,我担心创建和删除临时表的线程安全性.
假设我有一个存储过程,它创建了一些临时表,它甚至可以将临时表连接到其他临时表等.还可以说两个用户同时执行存储过程.
是否有可能一个用户运行sp并创建一个名为#temp的临时表,另一个用户运行相同的sp但是因为数据库中已经存在一个名为#temp的表而被停止了?
如果同一个用户在同一个连接上执行两次相同的存储过程怎么样?
是否有任何其他奇怪的场景可能导致两个用户查询相互干扰?
cas*_*One 34
对于第一种情况,不可能,因为#temp是本地临时表,因此对其他连接不可见(假设您的用户使用单独的数据库连接).临时表名称别名为生成的随机名称,并在引用本地临时表时引用该名称.
在您的情况下,由于您要在存储过程中创建本地临时表,因此在退出过程范围时将删除该临时表(请参阅"备注部分").
对于第二种情况,是的,您将收到此错误,因为该表已存在,并且该表持续的时间与连接一样长.如果是这种情况,那么我建议您在尝试创建表之前检查表是否存在.
创建本地范围的临时表(带有一个#),在它们的末尾带有一个标识符,使它们成为唯一的; 多个呼叫者(即使使用相同的登录名)也不应重叠.
(尝试一下:从两个连接和相同的登录创建相同的临时表.然后查询tempdb.dbo.sysobjects以查看创建的实际表...)
本地临时表是线程安全的,因为它们只存在于当前上下文中.请不要将上下文与当前连接混淆(来自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;
Run Code Online (Sandbox Code Playgroud)
简短的回答是:
每个查询都保证临时表的隔离,并且无需担心线程、锁或并发访问。
我不确定为什么这里的答案会谈论“连接”和线程的重要性,因为这些是编程概念,而查询隔离是在数据库级别处理的。
本地临时对象在 SQL Server 中由Session分隔。如果您同时运行两个查询,则它们是两个完全独立的会话,不会相互干扰。登录无关紧要,例如,如果您使用 ADO.NET 使用单个连接字符串(意味着多个并发查询将使用相同的 SQL 服务器“登录”),您的查询仍将在单独的会话中运行。连接池也无关紧要。本地临时对象(表和存储过程)是完全安全的,不会被其他会话看到。
阐明这是如何工作的;虽然您的代码对本地临时对象有一个单一的通用名称,但 SQL Server 会为每个会话的每个对象附加一个唯一的字符串,以将它们分开。您可以通过在 SSMS 中运行以下命令来查看这一点:
CREATE TABLE #T (Col1 INT)
SELECT * FROM tempdb.sys.tables WHERE [name] LIKE N'#T%';
Run Code Online (Sandbox Code Playgroud)
您将看到类似以下内容的名称:
然后,在不关闭该查询选项卡的情况下,打开一个新的查询选项卡并粘贴相同的查询并再次运行它。您现在应该会看到如下内容:
因此,每次您的代码引用#T 时,SQL Server 都会根据会话将其转换为正确的名称。分离都是自动处理的。