临时表是线程安全的吗?

发布于 2024-07-12 10:01:18 字数 341 浏览 14 评论 0原文

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

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

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

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

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

I'm using SQL Server 2000, and many of the stored procedures it use temp tables extensively. The database has a lot of traffic, and I'm concerned about the thread-safety of creating and dropping temp tables.

Lets say I have a stored procedure which creates a few temp tables, it may even join temp tables to other temp tables, etc. And lets also say that two users execute the stored procedure at the same time.

  • Is it possible for one user to run the sp and which creates a temp table called #temp, and the another user runs the same sp but gets stopped because a table called #temp already exists in the database?

  • How about if the same user executes the same stored procedure twice on the same connection?

  • Are there any other weird scenarios that might cause two users queries to interfere with one another?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

半透明的墙 2024-07-19 10:01:19

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

在您的情况下,由于您正在存储过程中创建本地临时表,退出过程范围时将删除该临时表(请参阅“备注部分”)。

在存储过程中创建的本地临时表将在存储过程完成时自动删除。 该表可以被创建该表的存储过程所执行的任何嵌套存储过程引用。 该表无法被调用创建该表的存储过程的进程引用。

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

For the first case, no, it is not possible, because #temp is a local temporary table, and therefore not visible to other connections (it's assumed that your users are using separate database connections). The temp table name is aliased to a random name that is generated and you reference that when you reference your local temp table.

In your case, since you are creating a local temp table in a stored procedure, that temp table will be dropped when the scope of the procedure is exited (see the "remarks section").

A local temporary table created in a stored procedure is dropped automatically when the stored procedure completes. The table can be referenced by any nested stored procedures executed by the stored procedure that created the table. The table cannot be referenced by the process which called the stored procedure that created the table.

For the second case, yes, you will get this error, because the table already exists, and the table lasts for as long as the connection does. If this is the case, then I recommend you check for the existence of the table before you try to create it.

╰ゝ天使的微笑 2024-07-19 10:01:19

本地范围的临时表(带有单个 #)是在其末尾带有标识符创建的,这使得它们是唯一的; 多个调用者(即使使用相同的登录名)不应重叠。

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

Local-scope temp tables (with a single #) are created with an identifier at the end of them that makes them unique; multiple callers (even with the same login) should never overlap.

(Try it: create the same temp table from two connections and same login. Then query tempdb.dbo.sysobjects to see the actual tables created...)

一口甜 2024-07-19 10:01:19

简短的回答是:

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

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

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

阐明其工作原理; 虽然您的代码对本地临时对象有一个通用的名称,但 SQL Server 会在每个会话的每个对象上附加一个唯一的字符串,以将它们分开。 您可以通过在 SSMS 中运行以下命令来查看这一点:

CREATE TABLE #T (Col1 INT)

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

您将看到类似于以下名称的内容:

T_______________00000000001F

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

T_______________00000000001F

T_______________000000000020

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

The short answer is:

Isolation of temporary tables is guaranteed per query, and there's
nothing to worry about either in regard to threading, locks, or
concurrent access.

I'm not sure why answers here talk about a significance of 'connections' and threads as these are programming concepts, whereas query isolation is handled at the database level.

Local temporary objects are separated by Session in SQL server. If you have two queries running concurrently, then they are two completely separate sessions and won't intefere with one another. The Login doesn't matter, so for example if you are using a single connection string using ADO.NET (meaning that multiple concurrent queries will use the same SQL server 'login'), your queries will all still run in separate sessions. Connection Pooling also doesn't matter. Local temporary objects (Tables and Stored Procedures) are completely safe from being seen by other sessions.

To clarify how this works; while your code has a single, common name for the local temporary objects, SQL Server appends a unique string to each object per each session to keep them separate. You can see this by running the following in SSMS:

CREATE TABLE #T (Col1 INT)

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

You will see something like the following for the name:

T_______________00000000001F

Then, without closing that query tab, open up a new query tab and paste in that same query and run it again. You should now see something like the following:

T_______________00000000001F

T_______________000000000020

So, each time your code references #T, SQL Server will translate it to the proper name based on the session. The separation is all handled auto-magically.

守护在此方 2024-07-19 10:01:19

本地临时表是线程安全的,因为它们仅存在于当前上下文中。 请不要将上下文与当前连接混淆(来自 MSDN:“A当存储过程完成时,在存储过程中创建的本地临时表会自动删除”),同一个连接可以安全地调用创建本地临时表的存储过程两次或多次(例如#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;

Local temp tables are thread-safe, because they only exist within the current context. Please don't confuse context with current connection (from MSDN: "A local temporary table created in a stored procedure is dropped automatically when the stored procedure is finished"), the same connection can safely call two or more times a stored procedure that creates a local temp table (like #TMP).

You can test this behavior by executing the following stored procedure from two connections. This SP will wait 30 seconds so we can be sure the two threads will be running their over their own versions of the #TMP table at the same time:

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;
痴梦一场 2024-07-19 10:01:19

临时表与会话相关联,因此如果不同的用户同时运行您的过程,则不会发生冲突...

Temp tables are tied to the session, so if different users run your procedure simultaneously there's no conflict...

酒解孤独 2024-07-19 10:01:19

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

Temp tables are created only in the context of the query or proc that creates them. Each new query gets a context on the database that is free of other queries' temp tables. As such, name collision is not a problem.

驱逐舰岛风号 2024-07-19 10:01:19

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

If you look in the temps database you can see the temporary tables there, and they have system generated names. So other than regular deadlocks you should be OK.

后来的我们 2024-07-19 10:01:19

除非您使用两个井号 ##temp ,否则临时表将是本地的,并且仅存在于与用户的本地连接中

unless you use two pound signs ##temp the temp table will be local and only exists for that local connection to the user

£烟消云散 2024-07-19 10:01:19

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

First let's make sure you are using real temp tables, do they start with # or ##? If you are creating actual tables on the fly and then dropping and recreating them repeatedly, you will indeed have problems with concurrent users. If you are createing global temp tables (ones that start with ##) you can also have issues. If you do not want concurrency issues use local temp tables (They start with #). It is also a good practice to explicitly close them at the end of the proc (or when they are no longer needed by the proc if you are talking long multi-step procs) and to check for existence (and drop if so) before creating.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文