【问题标题】:Delete vs Rollback Strategy - ETL Load删除与回滚策略 - ETL 加载
【发布时间】:2016-12-07 11:44:42
【问题描述】:

我正在通过以下方式将数据加载到表中:

DECLARE @srcRc INT;
DECLARE @dstRc INT;

SET @srcRc = ( SELECT COUNT(*) FROM A )

INSERT  INTO t
        (Col1
        ,Col2
        ,Col3
        )
        SELECT  A.Col1
               ,A.Col2
               ,B.Col3
        FROM    A
                JOIN B
                    ON A.Id = B.Id;

SET @dstRc = @@ROWCOUNT

现在我正在比较变量@srcRc@dstRcROWCOUNT 必须相同。如果不是,则需要删除插入的行。

Q1:回滚插入的行的最佳策略是什么?

我有几个想法:

1) 如果行数不匹配,则在事务中运行加载并回滚。
2) 将标志列(位)添加到名为toBeDeleted 的目标表中,运行加载,如果行数不匹配,则使用1 值更新toBeDeleted 列以将其标记为删除候选。然后以批处理模式(while-loop)删除。
或者不删除它们,但在使用t 表时始终从查询中排除删除候选者。
3)在插入行之前,先比较行数。如果不匹配,则不要启动加载。

DECLARE @srcRc INT;
DECLARE @dstRc INT;
SET @srcRc = ( SELECT   COUNT(1) FROM A );
SET @dstRc = ( SELECT   COUNT(1) FROM A JOIN B ON A.Id = B.Id );

Q2:对于更多的行,比方说 10-100 百万,有什么更好的解决方案?
Q3:或者对于类似的案例有没有更好的策略?

【问题讨论】:

    标签: sql-server etl sql-server-2016


    【解决方案1】:

    好的,假设:

    当表 A 和 B 的内容可能发生变化时,您需要回滚才能工作

    T 中可能还有其他行您不想作为回滚的一部分删除。

    然后您必须保留您插入的行的列表,因为您无法可靠地从 A 和 B 重新生成该列表,并且您不能只删除 T 中的所有内容

    你可以通过两种方式做到这一点

    • 更改您的导入,以便它首先将行插入到导入表中,保持导入表保持不变,直到您确定不再需要它为止。

    • 向 T [importId] 添加一个额外的列,您可以在其中放置一个唯一标识值

    显然第一种策略使用了更多的磁盘空间。因此,您保留数据的时间越长,数据越多,额外的列看起来就越好。

    另一种选择是单独生成导入数据的列表,并让您的事务 sql 成为批量插入,所有数据都硬编码到 sql 中。

    这适用于小型列表、初始设置数据等。


    编辑:

    从您的 cmets 看来,您本身并不想要回滚。但在导入过程中应用业务逻辑的最佳方式。

    在这种情况下,您的第三个答案是最好的。当您知道源数据不正确时,请勿进行导入。

    【讨论】:

    • 我只需要回滚“当前”负载,而不是历史记录。所以通常我每天都加载。今天我正在加载日期 N,明天 N+1。所以只检查当前批次的行数。如果行数不匹配,则需要擦除当前加载的所有行,而不仅仅是某些行。
    • 这些场景的问题在于它并不是真正的回滚,除非您撤消所做的任何事情。任何依赖简单行数的东西都可能出错。例如,您复制第 x 行并跳过第 y 行。您的行数将匹配
    • 确实如此,但这种情况从未发生过,我认为这种情况非常罕见。
    • 回滚是在出现问题的罕见情况下进行的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    • 2011-05-26
    • 1970-01-01
    • 2016-10-14
    • 2014-05-08
    • 2017-04-09
    相关资源
    最近更新 更多