存储过程中的临时表

时间:2009-05-13 11:30:46

标签: sql-server stored-procedures

我一直在想sp中的临时表以及所有这些都会影响并发性。 SP在MSSQL 08服务器上制作。

如果我有一个SP,我在其中创建一个临时表并再次删除它:

BEGIN

CREATE TABLE #MyTempTable
(
   someField int,
   someFieldMore nvarchar(50)
)

... Use of temp table here
... And then..

DROP TABLE #MyTempTable

END

这个SP会经常被调用,所以我的问题是这里是否会出现并发问题?

8 个答案:

答案 0 :(得分:31)

不。将为每个连接创建临时表的独立实例。

答案 1 :(得分:20)

可能。

以一个#(#example)为前缀的临时表基于每个会话保留。因此,如果您的代码在另一个调用正在运行时再次调用存储过程(例如后台线程),则create调用将失败,因为它已经存在。

如果您真的担心使用表变量

DECLARE @MyTempTable TABLE 
(
   someField int,
   someFieldMore nvarchar(50)
)

这将特定于该存储过程调用的“实例”。

答案 2 :(得分:7)

不是真的,我在谈论SQL Server。临时表(带有单个#)存在,并且在创建它的范围内可见(范围限制)。每次调用存储过程时,它都会创建一个新范围,因此临时表仅存在于该范围内。我相信临时表对于在该范围内调用的存储过程和udf也是可见的。但是,如果您使用双磅(##),那么它们会在您的会话中变为全局,因此作为创建临时表的会话的一部分对其他正在执行的进程可见,您将不得不考虑是否可以访问临时表同时也是可取的。

答案 3 :(得分:2)

对于所有建议使用表变量的人,请谨慎行事。表变量不能被索引,而临时表可以。使用少量数据时,表变量最佳,但如果您正在处理较大的数据集(例如50k记录),则临时表将比表变量快得多。

另请注意,您不能依赖try / catch强制在存储过程中进行清理。如果你想确定你可能需要创建一个可以对worker存储过程进行try / catch的包装存储过程,那么某些类型的失败不能在try / catch中捕获(例如,由于名称解析延迟导致编译失败)并在那里进行清理。

e.g。     创建proc worker AS     开始          - 在这做点什么     END

create proc wrapper AS
BEGIN
    Create table #...
    BEGIN TRY
       exec worker
       exec worker2 -- using same temp table
       -- etc
    END TRY
    END CATCH
       -- handle transaction cleanup here
       drop table #...
    END CATCH 
END

答案 4 :(得分:0)

根据SQL Server 2008 Books 您可以创建本地和全局临时表。本地临时表仅在当前会话中可见,并且全局临时表对所有会话可见。

' #table_temporal

' ## table_global

如果在存储过程或应用程序中创建了可由多个用户同时执行的本地临时表,则数据库引擎必须能够区分不同用户创建的表。数据库引擎通过在每个本地临时表名称内部附加数字后缀来完成此操作。

然后没有问题。

答案 5 :(得分:0)

简而言之:


说明

根据官方文档:https://docs.microsoft.com/en-us/sql/t-sql/statements/create-table-transact-sql?view=sql-server-ver15

<块引用>

如果在存储过程中创建了本地临时表或 可以由多个用户同时执行的应用程序, 数据库引擎必须能够区分由 不同的用户。数据库引擎通过内部执行此操作 将数字后缀附加到每个本地临时表名称。这 存储在 sysobjects 表中的临时表的全名 tempdb 由 CREATE TABLE 中指定的表名组成 语句和系统生成的数字后缀。为了允许 后缀,为本地临时名称指定的 table_name 不能超过 116 个字符。

答案 6 :(得分:-1)

数据库对所有#temp表使用相同的锁,因此如果您使用了很多,则会出现死锁问题。最好使用@ table变量进行并发。

答案 7 :(得分:-2)

尽可能使用@temp表 - 也就是说,您只需要一个主键,而不需要从下级存储过程访问数据。

如果您需要从下级存储过程访问数据(它是存储过程调用链的恶意全局变量),请使用#temp表,并且您没有其他干净的方法在存储过程之间传递数据。如果你需要一个二级索引也可以使用它(尽管如果你需要多个索引,真的问自己它是否是一个#temp表)

如果你这样做,总是在函数顶部声明你的#temp表。 SQL将在查看create table语句时强制重新编译存储过程....因此,如果在存储过程中间有#temp表声明,则存储过程必须停止处理并重新编译。

相关问题