2014-09-25 112 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) 

什么,你也可以做的是这些查询的检查执行计划 - 它会帮助你找到它的操作需要这么长。关于方面:如果可以避免使用游标,我通常会反对使用游标。