我需要修复一个prod数据库问题和清理脚本我已经花了很长时间。我尝试了几件没有运气的事情,以下是剧本:
DECLARE @ErrorMessage NVARCHAR(4000)
DECLARE @ErrorSeverity INT
DECLARE @ErrorState INT
DECLARE @ErrorProcedure NVARCHAR(50)
BEGIN TRY
IF OBJECT_ID('tempdb..#SuspectData') IS NOT NULL
BEGIN
DROP TABLE #SuspectData
END
CREATE TABLE #SuspectData
(
IID INT,
CID INT,
PID INT
)
INSERT INTO dbo.#SuspectData
SELECT DL.IID,DL.CID,IT.PID FROM DL
INNER JOIN IT ON IT.CID = DL.CID AND IT.IID = DL.IID
WHERE DL.Suspect = 1
WHILE (1 = 1)
BEGIN
BEGIN TRANSACTION
UPDATE TOP (5000) TDS
SET TDS.DTID = 4
FROM
TDS
INNER JOIN dbo.#SuspectData SD
ON TDS.IID = SD.IID AND TDS.PID = SD.PID
WHERE TDS.DTID <> 4
IF @@ROWCOUNT = 0
BEGIN
COMMIT TRANSACTION
BREAK
END
COMMIT TRANSACTION
END
WHILE (1 = 1)
BEGIN
BEGIN TRANSACTION
UPDATE TOP (5000) TDA
SET TDA.DTID = 4
FROM
TDA
INNER JOIN dbo.#SuspectData SD
ON TDA.IID = SD.IID AND TDA.PID = SD.PID
WHERE TDA.DTID <> 4
IF @@ROWCOUNT = 0
BEGIN
COMMIT TRANSACTION
BREAK
END
COMMIT TRANSACTION
END
DROP TABLE #SuspectData
END TRY
BEGIN CATCH
SELECT @ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorProcedure = ERROR_PROCEDURE()
RAISERROR (@ErrorMessage,@ErrorSeverity,@ErrorState,@ErrorProcedure) ;
END CATCH
我也有以下脚本同时更新所有内容,但它也花了很长时间,比如24小时或其他什么。
DECLARE @ErrorMessage NVARCHAR(4000)
DECLARE @ErrorSeverity INT
DECLARE @ErrorState INT
DECLARE @ErrorProcedure NVARCHAR(50)
BEGIN TRY
IF OBJECT_ID('tempdb..#SuspectData') IS NOT NULL
BEGIN
DROP TABLE #SuspectData
END
CREATE TABLE #SuspectData
(
IID INT,
CID INT,
PID INT
)
INSERT INTO dbo.#SuspectData
SELECT DL.IID,DL.CID,IT.PID FROM DL
INNER JOIN IT ON IT.CID = DL.CID AND IT.IID = DL.IID
WHERE DL.Suspect = 1
BEGIN TRANSACTION
--Update about 1.5M records
UPDATE TDS
SET TDS.DTID = 4
FROM
TDS
INNER JOIN dbo.#SuspectData SD
ON TDS.IID = SD.IID AND TDS.PID = SD.PID
WHERE TDS.DTID <> 4
COMMIT TRANSACTION
BEGIN TRANSACTION
--Update about 4.5M records
UPDATE TDA
SET TDA.DTID = 4
FROM
TDA
INNER JOIN dbo.#SuspectData SD
ON TDA.IID = SD.IID AND TDA.PID = SD.PID
WHERE TDA.DTID <> 4
COMMIT TRANSACTION
DROP TABLE #SuspectData
END TRY
BEGIN CATCH
SELECT @ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorProcedure = ERROR_PROCEDURE()
RAISERROR (@ErrorMessage,@ErrorSeverity,@ErrorState,@ErrorProcedure) ;
END CATCH
答案 0 :(得分:1)
我猜测TDS表很大。在这种情况下,您可以通过在临时表上创建索引来加速临时表和TDS之间的联接操作(ON TDS.IID = SD.IID和TDS.PID = SD.PID):
主要群集:
CREATE TABLE #SuspectData
(
IID INT,
CID INT,
PID INT,
CONSTRAINT pk_temp PRIMARY KEY(IID, PID)
)
或非群集(如果IID-PID对不唯一):
CREATE INDEX IDX_Temp_SuspectData ON #SuspectData(IID,PID)
您还可以检查这些查询的执行计划 - 它将帮助您找到需要这么长时间的操作。 另一方面:如果你能避免使用游标,我通常会反对使用游标。
答案 1 :(得分:0)
首先,是否有任何内容将DL.Suspect = 1
更改为其他内容?或者你的数据集是否会继续变大?
我也同意Sean Lange,更新必须是全部还是全部?
我建议使用cursor。游标是分解大型事务以加快使用和减少表锁的好方法。
DECLARE db_cursor CURSOR FOR SELECT DL.IID,DL.CID,IT.PID FROM DL
INNER JOIN IT ON IT.CID = DL.CID AND IT.IID = DL.IID
WHERE DL.Suspect = 1;
DECLARE @first INT;
DECLARE @second INT;
DECLARE @third INT;
OPEN db_cursor;
FETCH NEXT FROM db_cursor INTO @first , @second , @third ;
WHILE @@FETCH_STATUS = 0
BEGIN
-- Do your updates one row at a time here
UPDATE TDS
SET TDS.DTID = 4
FROM TDS
WHERE TDS.IID = @first AND TDS.PID = @third
WHERE TDS.DTID <> 4
END;
CLOSE db_cursor;
DEALLOCATE db_cursor;