SQL Server SELECT INTO 和临时表阻塞

Posted

技术标签:

【中文标题】SQL Server SELECT INTO 和临时表阻塞【英文标题】:SQL Server SELECT INTO and Blocking With Temp Tables 【发布时间】:2010-11-21 02:53:45 【问题描述】:

所以,最近一位 DBA 试图告诉我们,我们不能使用以下语法

SELECT X, Y, Z
INTO #MyTable
FROM YourTable

在我们的环境中创建临时表,因为该语法会在存储过程执行期间导致 TempDB 锁定。现在,我发现了许多详细说明临时表如何工作、执行范围、清理等的内容。但在我的一生中,我看不到任何关于阻塞的东西,因为它们的使用。

我们正在努力寻找证据证明我们不应该为所有临时表执行 CREATE TABLE #MyTable...,但双方都找不到证据。我正在寻找人们的任何见解。

附加信息

目前使用 SQL Server 2005,很快将使用 SQL Server 2008(企业版)

【问题讨论】:

【参考方案1】:

虽然 SELECT INTO 已解决阻止 tempdb 的问题,但我在编写此类代码时要小心,因为某些系统表确实被阻止了。

参考: http://www.sqlservercentral.com/Forums/Topic1642797-2799-1.aspx

【讨论】:

【参考方案2】:

SELECT INTO #temp_table 在语句执行期间在 tempdb 中持有一个 shema 锁,因为它完成的部分工作是创建表。这与首先​​使用CREATE TABLE #.... 创建表然后运行基于集合的INSERT 根本不同。 SELECT INTO 确实比 INSERT 有优势,特别是如果数据库的恢复模型是简单或批量日志,则该操作的日志记录最少。

【讨论】:

【参考方案3】:

如果您在事务中创建#temp 表,您可能会遇到阻塞。虽然通常不建议这样做,但我已经看到很多这样做了。

但是,这导致的阻塞发生在 tempdb 中的某些系统表上,这些系统表不会影响其他连接创建临时表(可能除了 2000 年之前的 SQL 版本?)。这确实意味着在 tempdb 上运行 sp_spacesused 将阻塞,除非您将事务隔离级别设置为未提交读取。同样,从 SSMS 查看 tempdb 上的属性也会失败并超时,因为它使用的是已提交的读取事务隔离级别。

【讨论】:

【参考方案4】:

为什么不做以下事情?

SELECT X, Y, Z
INTO #MyTable
FROM YourTable
WHERE 1 = 2

该语句将立即运行 - 创建您的临时表并避免任何可能的锁定。然后你可以像往常一样插入它:

INSERT #MyTable
SELECT X, Y, Z
FROM YourTable

【讨论】:

【参考方案5】:

这可能会漂浮很长时间,喂饱各种“顾问”的口袋。像所有的神话一样,它有一个真理的核心和大量的废话。

事实:SQL 2000 和以前的版本已知围绕 tempdb 中的范围分配存在争用问题。事实上,所有数据库中的争用都是正确的,但由于 tempdb 使用量很大,因此在 tempdb 中更为明显。它记录在KB328551:

当 tempdb 数据库严重时 使用过,SQL Server 可能会遇到 尝试分配时的争用 页。

来自 sysprocesses 系统表 输出,waitresource 可能会出现 作为“2:1:1”(PFS 页面)或“2:1:3”(SGAM 页)。根据程度 争用,这也可能导致 SQL 服务器出现无响应 短期。

这些操作大量使用 tempdb: 重复创建和删除临时 表(本地或全局)。 使用 tempdb 进行存储的表变量 目的。 与相关的工作表 光标。 与相关的工作表 一个 ORDER BY 子句。 与 GROUP BY 子句关联的工作表。 与 HASH PLANS 关联的工作文件。

大量使用这些 活动可能导致争用 问题。

在 SQL Server 2000 SP3 中添加了一个跟踪标志 -T1118,它强制 SQL 对混合页面分配使用循环算法。这种新算法与将 tempdb 部署在一组大小相等的文件(每个 CPU 一个)之上的做法相关联时,将减轻争用。跟踪标志仍然存在于 SQL 2005/2008 中,尽管它不太可能被需要。

关于这个神话的其他一切都非常荒谬。

使用#temp 表会导致阻塞吗?不会。在 SQL 2000 及更早版本中,它增加了负载下的争用,但这与说它阻止任何东西相去甚远。您必须先进行测量,看看是否是这种情况,如果是,请部署补救措施(为每个 CPU 分配一个 tempdb 文件,使它们大小相等,打开 -T1118).. select ... into #temp 在选择期间是否会阻塞某些内容?不是。 在包含选择的存储过程期间,select ... into #temp 是否会阻塞某些内容?一定不行。只是读到那个声明,我就笑了。

更多详情,有这篇文章:Misconceptions around TF1118。

【讨论】:

如果 [select ... into #temp] 在事务中,在事务提交之前,[select * from sysobjects] 将在任何其他会话中被阻塞。【参考方案6】:

这个建议一直在for a long time附近流传:

SQL Server 6.5 中的瓶颈

许多人使用 SELECT...INTO 查询 创建一个临时表,一些东西 像这样:

SELECT * INTO #TempTable FROM 源表

虽然这有效,但它会创建锁 针对 tempdb 数据库 SELECT 语句的持续时间 (如果你在拖网,很长一段时间 通过源中的大量数据 表,如果 SELECT...INTO 在开头 运行时间更长的显式事务) 当锁就位时,没有其他 用户可以创建临时表。这 瓶颈的实际位置是 锁定 tempdb 系统表。在以后 SQL Server 的版本,锁定 模型变了,问题是 避免。

幸运的是,这只是 SQL 6.5 的问题。它已在 7.0 及更高版本中修复。

【讨论】:

您能否使用 SQL 的新功能更新您的答案,因为您的答案首先出现在 Google 搜索中,并且它应该对最新版本有效。 TIA :) @RajShah 什么过时了?除非更高版本再次破坏它,否则我无法想象“它已在 7.0 及更高版本中修复”。是一个将过时的声明。 (而且“对于 6.5 来说是个问题”当然不能)。【参考方案7】:

如果这是真的,那么 mssql 就会出现问题,因为任何大型查询都可以使用 tempdb 来保存行的副本。这通常可以在查询计划中视为表假脱机,或者如果其存储桶的内存不足,则可以由 HASH JOIN 运算符使用。

您可以查看使用表变量,如果它们变大,mssql 将尝试将其存储在内存中并移动到 tempdb。

DECLARE @foo TABLE (x int, y int, z int)
INSERT INTO @foo(x, y, z) SELECT x, y, z FROM YourTable

当然,您应该先评估是否需要临时表和副本。尽管如果查询足够复杂以至于使用临时表更具可读性,那么它也可能足够复杂以至于值得使用临时表。

【讨论】:

【参考方案8】:

我会说缺乏锁定证明意味着没有锁定,这是你的证明。为什么创建临时表的方法(CREATE 或 SELECT ... INTO)会影响锁定 TempDB?

【讨论】:

这也是我们的想法和论点......但他们坚持认为使用 SELECT INTO 会导致存储过程期间的阻塞。 我想知道为什么临时表被锁定也是一个问题。如果是全局临时表,那就另当别论了。 @rexem:OP 的 DBA 并不是说​​临时表已锁定,而是说 TempDB、所有临时表的位置和其他临时存储已锁定。不知道DBA是否正确,我会听从更聪明的人的意见。

以上是关于SQL Server SELECT INTO 和临时表阻塞的主要内容,如果未能解决你的问题,请参考以下文章

使用 SELECT ... INTO 在 SQL Server 中创建表

SQL Server SELECT INTO 和临时表阻塞

在执行 SELECT INTO (SQL Server) 之前检查行的存在

避免在 SQL Server 中的 INSERT INTO SELECT 查询中重复

小5聊Sql Server基础之insert into select从一个表添加到另一个表

sql server 复制表结构