【问题标题】:Speed up MERGE in SQL Server on millions of rows在数百万行上加速 SQL Server 中的 MERGE
【发布时间】:2021-12-04 20:37:50
【问题描述】:

我正在尝试将数百万行插入/更新到已经包含数百万行的表中。

目标表包含一个 ID 列 (PK) 和许多其他列。

我正在将 csv 中的数据插入临时表 #temp(与目标表相同的列,除了 ID)。

然后我尝试合并它们,但合并速度非常慢(10M 行需要几个小时)。

-- Create temporal table #temp with almost all the columns in target_table
SELECT ColumnA,
        ColumnB,
        ColumnC,
        ColumnD,
        ColumnE,
        ColumnF,
        ColumnG,
        ColumnH
INTO #temp
FROM target_table
WHERE 1 = 2;

<HERE I DO A BULK INSERT INTO #temp WHICH ONLY TAKES A FEW SECONDS>

-- -- Merge into target_table
MERGE target_table AS TARGET
USING #temp AS SOURCE
ON (
            TARGET.ColumnA = SOURCE.ColumnA
        AND
            TARGET.ColumnB = SOURCE.ColumnB
        AND
            TARGET.ColumnC = SOURCE.ColumnC
        AND
            TARGET.ColumnE = SOURCE.ColumnE
    )
    
WHEN MATCHED
    AND (
            (TARGET.ColumnG IS NULL AND SOURCE.ColumnG IS NOT NULL OR TARGET.ColumnG <> SOURCE.ColumnG)
            OR
            (TARGET.ColumnH IS NULL AND SOURCE.ColumnH IS NOT NULL OR TARGET.ColumnH <> SOURCE.ColumnH)
        )
    THEN
    UPDATE SET TARGET.ColumnG = SOURCE.ColumnG, TARGET.ColumnH = SOURCE.ColumnH

WHEN NOT MATCHED BY TARGET
    THEN
    INSERT (ColumnA, ColumnB, ColumnC, ColumnD, ColumnE, ColumnF, ColumnG, ColumnH)
    VALUES (SOURCE.ColumnA, SOURCE.ColumnB, SOURCE.ColumnC, SOURCE.ColumnD, SOURCE.ColumnE, SOURCE.ColumnF,
            SOURCE.ColumnG, SOURCE.ColumnH);

在批量插入之后,MERGE 的执行计划有一些非常昂贵的排序(占总成本的 41%)。

关于如何加快合并的任何建议?

谢谢!

【问题讨论】:

  • 请将您的表和索引定义添加到您的问题中,并通过brentozar.com/pastetheplan 分享查询计划,否则我们无法提供任何明确的帮助。您可能希望在两个表上都有一个聚集索引(ColumnA, ColumnB, ColumnC, ColumnE)
  • 什么是相对的“百万”?如果您要更新/插入太多以至于几乎所有数据都被重写,那么要考虑的一个选项是完全构建一个新表(SELECT 现有数据,与新数据结合,然后批量插入),然后使用sp_renametruncatealter table .. switch 完全替换原始表。这是否更快取决于,但是与更复杂的操作相比,批量插入在速度方面很难被击败,并且在停机时间方面也很难被击败。

标签: sql sql-server indexing merge sqlperformance


【解决方案1】:

向#temp 表插入数据后,您可以为临时表创建聚集索引:

CREATE CLUSTERED INDEX tbl_temp_index ON #temp (ColumnA, ColumnB, ColumnC, ColumnE);  

这提高了连接过程中的性能。 如果您也可以为 target_table 创建相同的索引,那就太好了。

如果您可以将ColumnGColumnH 上的NULL 值更新为默认值,那么您可以替换此条件:

 (TARGET.ColumnG IS NULL AND SOURCE.ColumnG IS NOT NULL OR TARGET.ColumnG <> SOURCE.ColumnG)
 OR
 (TARGET.ColumnH IS NULL AND SOURCE.ColumnH IS NOT NULL OR TARGET.ColumnH <> SOURCE.ColumnH)

到:

    (TARGET.ColumnG <> SOURCE.ColumnG)
    OR
    (TARGET.ColumnH <> SOURCE.ColumnH)  

我已经在我的电脑上测试了这个查询。我创建了这些表并将 10 M 样本记录插入到表中。但我不知道你的ColumnsAColumnsB 字段的类型是什么,我为这些字段设置了整数类型。在我的计算机应用程序上执行此查询 (create temp file, insert 10 M from CSV, and merge tables) 的持续时间。 20-25 秒。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多