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);
我们在 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);