【问题标题】:Cascading deletes in PostgreSQLPostgreSQL 中的级联删除
【发布时间】:2010-09-07 22:03:44
【问题描述】:

我有一个包含几十个表的数据库,这些表通过外键相互关联。在正常情况下,我想要这些约束的默认 ON DELETE RESTRICT 行为。但是当尝试与顾问共享数据库快照时,我需要删除一些敏感数据。我希望我对DELETE FROM Table CASCADE 命令的记忆不是纯粹的幻觉。

我最终做的是转储数据库,编写一个脚本来处理转储,通过添加ON DELETE CASCADE 子句和所有外键约束,从中恢复,执行我的删除,再次转储,删除ON DELETE CASCADE,最后再次恢复。这比我在 SQL 中编写删除查询要容易——删除整个数据库切片不是正常操作,因此架构并不完全适应它。

下次出现这种情况时,有人有更好的解决方案吗?

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:
    TRUNCATE table CASCADE;
    

    我是 Postgres 新手,所以我不确定 TRUNCATE 与 DROP 的权衡。

    【讨论】:

    • 截断将保留表格。 Drop 将删除表本身。
    【解决方案2】:

    TRUNCATE 只是从表中删除数据并离开结构

    【讨论】:

      【解决方案3】:

      您可以将外键约束创建为 DEFERRABLE。然后,您可以在清理数据时暂时禁用它们,并在完成后重新启用它们。看看this question

      【讨论】:

        【解决方案4】:

        您不需要转储和恢复。您应该能够只删除约束,使用级联重建它,执行删除,再次删除它,然后使用限制重建它。

        CREATE TABLE "header"
        (
          header_id serial NOT NULL,
          CONSTRAINT header_pkey PRIMARY KEY (header_id)
        );
        
        CREATE TABLE detail
        (
          header_id integer,
          stuff text,
          CONSTRAINT detail_header_id_fkey FOREIGN KEY (header_id)
              REFERENCES "header" (header_id) MATCH SIMPLE
              ON UPDATE NO ACTION ON DELETE NO ACTION
        );
        insert into header values(1);
        insert into detail values(1,'stuff');
        delete from header where header_id=1;
        alter table detail drop constraint detail_header_id_fkey;
        alter table detail add constraint detail_header_id_fkey FOREIGN KEY (header_id)
              REFERENCES "header" (header_id) on delete cascade;
        delete from header where header_id=1;
        alter table detail add constraint detail_header_id_fkey FOREIGN KEY (header_id)
              REFERENCES "header" (header_id) on delete restrict;
        

        【讨论】:

          【解决方案5】:

          我认为您不需要像那样处理转储文件。做一个流转储/恢复,并处理它。比如:

          createdb -h scratchserver scratchdb
          createdb -h scratchserver sanitizeddb
          
          pg_dump -h liveserver livedb --schema-only | psql -h scratchserver sanitizeddb
          pg_dump -h scratchserver sanitizeddb | sed -e "s/RESTRICT/CASCADE/" | psql -h scratchserver scratchdb
          
          pg_dump -h liveserver livedb --data-only | psql -h scratchserver scratchdb
          psql -h scrachserver scratchdb -f delete-sensitive.sql
          
          pg_dump -h scratchserver scratchdb --data-only | psql -h scratchserver sanitizeddb
          pg_dump -Fc -Z9 -h scratchserver sanitizedb > sanitizeddb.pgdump
          

          在 delete-sensitive.sql 中存储所有 DELETE sql 的位置。如果您不介意顾问使用 CASCADE 外键而不是 RESTRICT 外键获取数据库,则可以删除 sanitizeddb 数据库/步骤。

          可能还有更好的方法,具体取决于您需要执行此操作的频率、数据库的大小以及敏感数据的百分比,但我想不出更简单的方法来执行此操作一次或两次用于大小合理的数据库。毕竟你需要一个不同的数据库,所以除非你已经有一个 slony 集群,否则无法避免转储/恢复周期,这可能很耗时。

          【讨论】:

            【解决方案6】:

            @Tony:不,模式很有用,事实上,我们使用它们来对数据库中的数据进行分区。但我说的是在让顾问拥有数据库副本之前尝试清理敏感数据。我希望这些数据消失。

            【讨论】:

              【解决方案7】:

              您可能想研究在 PostgreSQL 中使用 schemas。我在过去的项目中这样做是为了让不同的人群或开发人员拥有自己的数据。然后,您可以使用脚本为此类情况创建数据库的多个副本。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-08-31
                • 1970-01-01
                • 2019-04-26
                • 2011-10-12
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多