【问题标题】:Deleting records from one table joined onto another table SQL从一个连接到另一个表 SQL 的表中删除记录
【发布时间】:2020-01-25 17:07:01
【问题描述】:

我有两张表,一张有 212,000 条记录(已弃用的记录),另一张有 10,500,000 条记录

我想在 id 和 version_number 字段上加入这两个表,因为这两个表都有这些字段。我希望可以从连接表中删除匹配的记录(从连接表中),即从 10,500,000 条记录中删除所有 212,000 条记录

我想知道使用 Oracle SQL 的最佳方法是什么?我见过 使用单个字段使用内部连接的示例,并且使用删除语句从表 2 中删除 table1,但没有看到使用两个字段的示例(在连接中)。

在删除记录之前使用外部联接是否有意义?我在想这可能有助于我跟踪已删除的内容(如果可能)

【问题讨论】:

    标签: sql oracle sql-delete


    【解决方案1】:

    您不需要使用OUTER JOIN,除了检查将相应的行数。 不会被删除。

    此类查询的示例见下文(我使用答案末尾提供的生成的测试数据)

    with del as (
    select delta.id, delta.version,
    decode(big.id,null,0,1) is_deleted
    from delta
    left outer join big 
    on delta.id = big.id and delta.version = big.version
    )
    select is_deleted, count(*) cnt, max(id||'.'||version) eg_id_vers
    from del
    group by is_deleted;
    
    IS_DELETED        CNT  EG_ID_VERS                                                                   
    ---------- ---------- ----------
             1      20000 99995.0   
             0         20 100100.0   
    

    根据您的数据大小,您应该在两个表上使用HASH JOINfull table scan 以获得可接受的性能。

    DELETE基本上有两种选择

    可更新的加入视图

    请注意,在这种情况下,您的小表必须具有唯一索引 ID, VERSION(或主键)

    create unique index delta_idx on delta(id,version);
    

    相反,BIG 表应该没有这样的约束。这很重要,因为它清楚地表明您的 BIG 表是连接视图中唯一的一个键保留表

    简单地加入小表由于唯一约束

    ,不能从大表复制行

    有关更新加入视图

    的更多信息,请参阅here
    delete from 
    (
    select delta.id, delta.version, big.id big_id, big.version
    from big 
    join delta 
    on delta.id = big.id and delta.version = big.version
    )
    

    上面的delete 会从BIG 表中删除行,因为这是唯一的键保留表(参见上面的讨论)

    此 DML 导致 HASH JOIN

    使用 EXISTS 删除

    如果您的小表没有主键(即它可以包含具有相同ID and VERSION 的重复行),您必须回退other answer 中提出的解决方案。

    DELETE FROM big 
        WHERE EXISTS (SELECT null
                      FROM delta
                      WHERE delta.id = big.id and delta.version = big.version
                     ) 
    

    不需要索引,您应该期待一个带有HASH JOIN RIGHT SEMI 的执行计划,这意味着这两种方法并没有真正的不同。

    测试样本数据

    create table big as
    select 
    trunc(rownum/10) id, mod(rownum,10) version,
    lpad('x',10,'Y') pad
    from dual connect by level <= 1000000;
    
    /* the DELTA table has 50 times less rows,
    allow some rows out of range of the BIG table - those rows will not be deleted **/
    drop table delta;
    create table delta as
    select 
    trunc(rownum*50/10) id, mod(rownum*50,10) version
    from dual connect by level <= 1001000/50;
    
    create unique index delta_idx on delta(id,version);
    

    【讨论】:

    • 感谢 Marmite Bomber 的出色回答和解释!我会尝试两种方法
    【解决方案2】:

    一个简单的方法就是使用INEXISTS

    DELETE FROM bigtable bt
        WHERE EXISTS (SELECT 1
                      FROM littletable lt
                      WHERE bt.? = lt.?
                     );
    

    您希望在 littletable 上为关联子句使用的键建立索引。

    【讨论】:

    • 谢谢戈登!我想知道在 select 子句中是否存在 bt.? - 不?表示两个表之间的公共字段,即 id 和版本号字段?还是我需要明确说明,即 WHERE bt.id = lt.id 和 bt.versionnumber = lt.versionnumber ? EXISTS 是否也比其他方法提供更好的性能?
    • @daveb 。 . .您的问题不清楚这些表格是如何相关的。如果您想要特定数据的特定答案,请提出 问题。提供样本数据、期望的结果以及您需要的逻辑解释。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    • 1970-01-01
    相关资源
    最近更新 更多