[英]SQL DB script performance tuning
我需要解決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
我猜TDS表很大。 在這種情況下,可以通過在臨時表上創建索引來加快臨時表和TDS之間的聯接操作(在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)
您還可以做的是檢查那些查詢的執行計划-這將幫助您找到需要花費很長時間的操作。 側面:如果可以避免的話,我通常不建議使用游標。
首先,是否有什么可以將DL.Suspect = 1
更改為其他內容? 還是您的數據集越來越大?
我也同意肖恩·蘭格(Sean Lange)的觀點,是全部更新還是全部刪除?
我建議使用游標 。 游標是拆分大型事務以加快使用速度並減少表鎖定的好方法。
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.