【问题标题】:Circular delete cascade in PostgresPostgres中的循环删除级联
【发布时间】:2021-11-25 23:59:10
【问题描述】:

(作为背景,我使用的是 Postgres 12.4)

我不清楚为什么在两个表之间存在循环 FK 并且两个 FK 都设置为 ON DELETE CASCADE 时删除工作。

CREATE TABLE a (id bigint PRIMARY KEY);
CREATE TABLE b (id bigint PRIMARY KEY, aid bigint references a(id) on delete cascade);
ALTER TABLE  a ADD COLUMN bid int REFERENCES b(id) ON DELETE CASCADE ;

insert into a(id) values (5);
insert into b(id, aid) values (10,5);
update a set bid = 10 where id=5;

DELETE from a where id=5;

我正在考虑的方式是,当您删除表“a”中 PK id = 5 的行时,postgres 会查看具有引用约束的表,该引用约束引用 a(id),它找到 b,它尝试删除表 b 中 id = 10 的行,但是它必须查看引用 b(id) 的表,所以它会返回到 a,然后它应该只是以无限循环结束。

但情况似乎并非如此。删除完成,没有错误。 正如一些消息来源在网上所说的那样,您也不能创建循环约束。约束已成功创建,且均不可延迟。

所以我的问题是 - 为什么 postgres 会完成这个循环级联,即使两个约束都没有设置为可延迟,如果它能够这样做,那么即使有 DEFERRABLE 选项又有什么意义呢?

【问题讨论】:

    标签: database postgresql cascade postgresql-12


    【解决方案1】:

    外键约束被实现为系统触发器。

    对于ON DELETE CASCADE,此触发器将运行如下查询:

    /* ----------
     * The query string built is
     *  DELETE FROM [ONLY] <fktable> WHERE $1 = fkatt1 [AND ...]
     * The type id's for the $ parameters are those of the
     * corresponding PK attributes.
     * ----------
     */
    

    查询运行的是一个新的数据库快照,所以它看不到被之前的 RI 触发器删除的行:

    /*
     * In READ COMMITTED mode, we just need to use an up-to-date regular
     * snapshot, and we will see all rows that could be interesting. But in
     * transaction-snapshot mode, we can't change the transaction snapshot. If
     * the caller passes detectNewRows == false then it's okay to do the query
     * with the transaction snapshot; otherwise we use a current snapshot, and
     * tell the executor to error out if it finds any rows under the current
     * snapshot that wouldn't be visible per the transaction snapshot.  Note
     * that SPI_execute_snapshot will register the snapshots, so we don't need
     * to bother here.
     */
    

    这样可以确保没有 RI 触发器会再次尝试删除同一行,从而破坏循环性。

    (所有引用均来自src/backend/utils/adt/ri_triggers.c。)

    【讨论】:

      猜你喜欢
      • 2020-09-20
      • 2019-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-12
      • 1970-01-01
      • 1970-01-01
      • 2010-09-07
      相关资源
      最近更新 更多