28

所以,最近一个 DBA 试图告诉我们,我们不能使用

SELECT X, Y, Z
INTO #MyTable
FROM YourTable

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

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

附加信息

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

4

8 回答 8

35

这个建议已经流传了很长时间

SQL Server 6.5 中的瓶颈

许多人使用 SELECT...INTO 查询来创建临时表,如下所示:

从 SourceTable 中选择 * INTO #TempTable

虽然这可行,但它会在 SELECT 语句的持续时间内创建对 tempdb 数据库的锁定(如果您正在搜索源表中的大量数据,则需要相当长的时间,如果 SELECT...INTO 位于开始时,则更长的时间)长时间运行的显式事务)当锁到位时,其他用户不能创建临时表。瓶颈的实际位置是 tempdb 系统表上的锁。在更高版本的 SQL Server 中,锁定模型发生了变化,并且避免了该问题。

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

于 2009-08-19T21:43:02.373 回答
17

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

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

当 tempdb 数据库被大量使用时,SQL Server 在尝试分配页面时可能会遇到争用。

从 sysprocesses 系统表输出中,waitresource 可能显示为“2:1:1”(PFS 页面)或“2:1:3”(SGAM 页面)。根据争用的程度,这也可能导致 SQL Server 在短时间内出现无响应。

这些操作大量使用 tempdb:
重复创建和删除临时表(本地或全局)。
使用 tempdb 进行存储的表变量。
与 CURSORS 关联的工作表。
与 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 在包含选择的存储过程期间是否会阻塞某些内容?一定不行。只是读到那个说法,我就笑了。

有关详细信息,请参阅这篇文章:围绕 TF1118 的误解

于 2009-08-20T00:30:18.980 回答
10

为什么不执行以下操作?

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

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

INSERT #MyTable
SELECT X, Y, Z
FROM YourTable
于 2010-06-15T21:52:21.407 回答
1

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

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

于 2010-11-02T00:03:37.353 回答
1

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

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

于 2016-03-10T13:06:44.207 回答
0

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

于 2009-08-19T21:24:53.360 回答
0

好吧,如果这是真的,那么 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

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

于 2009-08-19T21:42:22.903 回答
0

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

于 2010-01-22T20:16:43.703 回答