SQL 使用涉及 NVARCHAR(MAX) 列气球 TEMPDB 的连接进行更新

SQL Update with join involving NVARCHAR(MAX) column balloons TEMPDB

以下查询导致 SQL Server 2014 TEMPDB.MDF 增长到 40Gb,并且需要大约一个小时才能达到 运行。

对非 NVARCHAR(MAX) 列的类似查询需要几分钟时间。

正在更新的 table 大约有 700 万行。

在最后添加 AND C.SQLStmt IS NOT NULL 改善了这一点。

如有任何帮助,我们将不胜感激。

UPDATE R 
SET    R.SQLStmt = C.SQLStmt 
FROM SampleResults R 
  JOIN SampleTests T ON T.SampleCode = R.SampleCode 
                    AND T.TestPosition = R.TestPosition 
  JOIN TestComponents C ON T.TestCode = C.TestCode 
                       AND T.TestVersion = C.AuditNumber 
                       AND R.ComponentColumn = C.ComponentColumn 
                       AND R.ComponentRow = C.ComponentRow 
WHERE T.AuditFlag = 0 
AND   R.AuditFlag = 0 
AND   C.SQLStmt IS NOT NULL

这是 this question 的后续内容,我没有足够的声誉来评论它。

执行计划为:

Update
Cost: 0%
 |
Cluseterd Index Updated
[SampleResults].[pk_SampleResults]
Cost: 27%
 |
Top
COST: 0%
 |
Sort
(Distinct Sort)
Cost: 31%
 |
Nested Loops   Index Seek (NonClustered)
(Inner Join) - [SampleTests].[SampleTestsAuditFlag...
Cost: 0%       Cost: 10%
 |
Nested Loops   Key Lookup (Clustered)
(Inner Join) - [SampleResults].[pk_SampleResults]...
Cost: 0%       Cost: 15%
 |
Nested Loops   Index Seek (NonClustered)
(Inner Join) - [SampleResults].[SampleResultsCompo...
Cost: 0%       Cost: 9%
 |
Filter
Cost: 0%
 |
Clustered Index Scan (Clustered)
[TestComponents].[pk_TestComponents...
Cost: 9%

因为该列实际存储数据的最大大小只有392个字符,所以最终的解决方案是:

1) 暂时将源列和目标列(SampleResults.SQLStmt 和 TestComponents.SQLStmt)的大小更改为 392 个字符。 2)进行更新。 3) 将源列和目标列的大小更改为新的更合理的 4000 个字符大小。

DECLARE @tempSQLStmtLength SMALLINT = (SELECT MAX(LEN(SQlStmt)) FROM TestComponents WHERE SQlStmt IS NOT NULL)
IF @tempSQLStmtLength IS NOT NULL AND @tempSQLStmtLength > 0
BEGIN
  -- Temporarily reduce size of SQLStmt columns so that update is as quick as possible.
  EXEC('ALTER TABLE SampleResults ALTER COLUMN SQLStmt NVARCHAR(' + @tempSQLStmtLength +') NULL')
  EXEC('ALTER TABLE TestComponents ALTER COLUMN SQLStmt NVARCHAR(' + @tempSQLStmtLength + ') NULL')

  -- Perform update.
  UPDATE R SET R.SQLStmt = C.SQLStmt FROM SampleResults R JOIN SampleTests T ON T.SampleCode = R.SampleCode AND T.TestPosition = R.TestPosition JOIN TestComponents C ON (T.TestCode = C.TestCode OR T.TestCode + '-' + CAST(T.TestPosition AS VARCHAR(5)) + '-' + T.SampleCode = C.TestCode) AND T.TestVersion = C.AuditNumber AND R.ComponentColumn = C.ComponentColumn AND R.ComponentRow = C.ComponentRow WHERE T.AuditFlag = 0 AND R.AuditFlag = 0 AND C.SQLStmt IS NOT NULL

  -- Now that update is finished, set SQLStmt columns to their final new size.
  ALTER TABLE SampleResults ALTER COLUMN SQLStmt NVARCHAR(4000) NULL
  ALTER TABLE TestComponents ALTER COLUMN SQLStmt NVARCHAR(4000) NULL
END;

TEMPDB.MDB 只增长到 2.8Gb,花了几分钟。