包含NVARCHAR(MAX)列的连接的SQL更新气球TEMPDB

时间:2018-03-23 16:48:08

标签: sql-server nvarchar tempdb

以下查询导致SQL Server 2014 TEMPDB.MDF增长到40Gb并运行大约一个小时。

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

正在更新的表格大约有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%

1 个答案:

答案 0 :(得分:0)

由于列中存储的实际数据的最大大小仅为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并花了几分钟。