估计单个事务的事务日志大小

Bar*_*z X 3 sql-server transaction-log

今天我尝试对 50M+ 行执行更新操作,例如:

UPDATE [table] SET [Column] += 1;
Run Code Online (Sandbox Code Playgroud)

等待 30 分钟后,我看到日志已开始自行填充,再过 30 分钟后,由于日志已满,整个事务回滚。DB 处于简单恢复模式,但这毫无意义,因为这是作为单个事务完成的。SQL Server 本身无法预测它会使用整个日志大小(可以说它为此被锁定了大小),但是我向您提问,亲爱的有经验的 DBA - 您能预测这个大小吗?有没有办法计算这样的估计?

更新:

是的,我了解这个过程,我知道我可以批量处理,我也知道如何让它表现良好。我真正的问题是日志大小将有多大?您将如何计算简单表的更新,例如:

CREATE TABLE [TABL] ([ID] int identity(1,1) PRIMARY KEY CLUSTERED, [X] int not null);

INSERT INTO [TABL] VALUES(1)
GO 1000

UPDATE [TABL]
SET [X] = 2;
Run Code Online (Sandbox Code Playgroud)

在我的测试盒上,操作的更新部分是 6 页大 = 48KB。当我对 10k 行重复相同的操作时,我收到了 144 页的事务日志。对于 100k 行,它是 1314 页,对于 1M,它是 13970 页。这表明我们可以将其视为线性函数(因为我们有额外的页面,无论如何都必须存在,无论我们是否更新任何内容 --> 2-3 页)。

回到开始,我知道我可以在总操作的 5% 上运行一个批处理,检查页面 chenge 内容(如Paul Randal 的博客):

    DECLARE @Extent_ID              INT;
    DECLARE @Size_Total             BIGINT = 0;
    DECLARE @File_ID                INT;
    DECLARE @File_Size_Pages        INT;

    DECLARE @Log_Page_ID            INT;
    DECLARE @Log_Total              BIGINT = 0;
    DECLARE @Log_Total_Changed      BIGINT;
    DECLARE @DBCC_PAGE_String_Log   VARCHAR (200);




    DECLARE [files] CURSOR FOR

        SELECT [file_id], [size] 
        FROM master.sys.master_files
        WHERE [type_desc] = N'ROWS'
        AND [state_desc] = N'ONLINE'
        AND [database_id] = DB_ID(@DB_Name);

    OPEN files;

    FETCH NEXT FROM [files] INTO @File_ID, @File_Size_Pages;

    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @Extent_ID = 0;
        SET @Size_Total += @File_Size_Pages / 8;    --| Convert size in pages to to extents

        WHILE (@Extent_ID < @File_Size_Pages)
        BEGIN

             SELECT @Log_Page_ID = @Extent_ID + 7;

             SELECT @DBCC_PAGE_String_Log = 'DBCC PAGE ([' + @DB_Name + '], ' + CAST (@File_ID AS VARCHAR) + ', ' + CAST (@Log_Page_ID AS VARCHAR) + ', 3) WITH TABLERESULTS, NO_INFOMSGS';

             TRUNCATE TABLE [msdb].[dbo].[DBCC_Page_Check];
             INSERT INTO [msdb].[dbo].[DBCC_Page_Check] EXEC (@DBCC_PAGE_String_Log);

             SELECT @Log_Total_Changed = SUM ([msdb].[dbo].[Extent_Change_Checks] ([Field]))
             FROM [msdb].[dbo].[DBCC_Page_Check]
             WHERE [VALUE] = '    MIN_LOGGED'
             AND [ParentObject] LIKE 'ML_MAP%';

             SET @Log_Total += @Log_Total_Changed;

             SET @Extent_ID += 511232;
      END
----------------------------------------------------------------------------------------------------------------------------

        FETCH NEXT FROM [files] INTO @File_ID, @File_Size_Pages;
    END;

    DROP TABLE [msdb].[dbo].[DBCC_Page_Check];
    CLOSE [files];
    DEALLOCATE [files];
Run Code Online (Sandbox Code Playgroud)

但这仍然需要进行更改(即使有回滚),然后我们才能进行任何估计。再说一次 - 有没有人知道如何比上面的方法更好地估计它 - 预先?

Kin*_*hah 5

有没有办法计算这样的估计?

不,你无法预测。您应该始终批量更新或删除。