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,花了几分钟。
以下查询导致 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,花了几分钟。