2014-09-25 111 views
0

我需要修復prod數據庫問題和清理腳本,我已經花了很長時間。我試過幾件事情沒有任何的運氣,下面是腳本:SQL數據庫腳本性能調整

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 
+1

您的交易需要分解成幾部分。您編寫代碼的方式實際上比較低的腳本慢,因爲事務大小相同,但是您使用循環減慢了速度。此更新是否需要全部或全無,或者是否可以分解成可管理的塊?從我所看到的沒有理由使用自己的事務,你沒有任何地方單一的回滾。而WHILE 1 = 1?認真??? – 2014-09-25 14:11:59

+1

並索引你的臨時表,如果數據集很大並且它所連接的表很大,coudl會幫助很多人。 – HLGEM 2014-09-25 14:44:56

回答

0

首先,有沒有什麼改變DL.Suspect = 1到別的東西?或者你的數據集是否越來越大?

我也同意肖恩蘭格,更新必須是全部或沒有?我想推薦使用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; 
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) 

什麼,你也可以做的是這些查詢的檢查執行計劃 - 它會幫助你找到它的操作需要這麼長。關於方面:如果可以避免使用遊標,我通常會反對使用遊標。