SQL 服务器中的交易速度变慢

Transactions getting slower in SQL Server

我们在 SQL 服务器中使用完全恢复模式。我们有一项工作从分期 table 合并到最终 table。暂存 table 包含数百万行。最后的 table 也很大,有数百万行。我们正在分批合并 10,000 行。

下面给出了单个批次的伪代码:

BEGIN TRANSACTION

DELETE TOP 10000 * 
FROM <Staging Table> 
OUTPUT deleted.* INTO @TableVariable

MERGE INTO <Final Table> 
USING @TableVariable

COMMIT TRANSACTION

问题是,对于每个新批次,批处理操作越来越慢。当我们重新启动服务器时,批处理再次变得更快。事务也没有写入磁盘并且需要很长时间才能插入到磁盘。我们怀疑这是事务日志的问题。当我们减小批处理大小时,会发生更多事务并且批处理速度会变慢。

有没有办法提高这种批量删除和合并操作的性能?您是否建议使用 CHECKPOINT 强制进入完全恢复模式?

我们所做的是,我们没有强制执行 CHECKPOINT 过程,而是在 WHILE 循环中引入了人为延迟,这样事务就不会受到限制。

由于 SQL 服务器环境中的事务限制,我们能够解决内存不足问题。我们在暂存中有数百万行 table。引入的 10,000 批处理和延迟确保我们不会使服务器过载。有人访问服务器。


DECLARE @RowCount INT;

SET @RowCount = (SELECT COUNT(*) FROM StagingTable);

WHILE (@RowCount > 0)
BEGIN

    BEGIN TRANSACTION

    DELETE TOP 10000 * 
    FROM <Staging Table> 
    OUTPUT deleted.* INTO @TableVariable

    MERGE INTO <Final Table> 
    USING @TableVariable

    COMMIT TRANSACTION

    WAITFOR DELAY '00:00:10'; --artificially introduce 10 seconds delay

    SET @RowCount = (SELECT COUNT(*) FROM StagingTable);

END 

通常可以通过避免多余的更新来改进合并操作。如果因为目标行和源行相等而没有要更新的内容,则不要更新该行。这对于大多数行没有更改的情况非常有效,因为 SQL 服务器在事务日志中写入的信息要少得多。

为避免对合并操作进行过多更新,请像这样编写合并语句:

MERGE INTO target AS t
USING source AS s
ON t.id = s.id
WHEN MATCHED 
  AND ((t.col1 <> s.col1 
       OR t.col1 IS NULL AND s.col1 IS NOT NULL
       OR t.col1 IS NOT NULL AND s.col1 IS NULL)
  OR (t.col2 <> s.col2 
       OR t.col2 IS NULL AND s.col2 IS NOT NULL
       OR t.col2 IS NOT NULL AND s.col2 IS NULL)
  OR (t.col2 <> s.col3 
       OR t.col3 IS NULL AND s.col3 IS NOT NULL
       OR t.col3 IS NOT NULL AND s.col3 IS NULL))
THEN UPDATE SET
  col1 = s.col1, col2 = s.col2, col3 = s.col3
WHEN NOT MATCHED BY TARGET THEN 
    INSERT (id, col1, col2, col3)
    VALUES (s.id, s.col1, s.col2, s.col3);