【问题标题】:Django 1.2 PostgreSQL cascading delete for keys with ON DELETE NO ACTIONDjango 1.2 PostgreSQL级联删除带有ON DELETE NO ACTION的键
【发布时间】:2011-11-11 10:31:56
【问题描述】:

我有一个包含大约 150 个表的 postgresql 数据库(这是一个 Django 1.2 项目)。 Django 在创建表时将ON DELETE NO ACTIONON UPDATE NO ACTION 添加到外键。

现在我需要根据特定条件从一堆表中批量删除数据(大约 800,000 条记录)。

使用Model.objects.filter().delete() 不是一种选择,因为数据量很大并且需要很长时间。

只有最合理的选项似乎是级联删除,但由于 Django 添加了“ON DELETE NO ACTION”,它似乎是一个没有选项。

所以我的问题是:有什么方法可以轻松地将所有外键更改为 ON DELETE CASCADE(其中有很多)或类似的方法。

(我知道我可以为每个表手动编写 SQL 查询,但这将是一项艰巨且难以维护的任务。)

【问题讨论】:

    标签: django postgresql cascading-deletes


    【解决方案1】:
    【解决方案2】:

    正如包含 Andrew 答案的链接中所指出的,如果您在 Django 中将其设置为 CASCADE,那么 Django 将执行删除“零售”。如果它设置为NO ACTION,你可以创建一个数据库级的外键定义来处理事情。对我来说,这听起来是一个合理的计划。

    确保您在每个外键的引用列集上定义了一个索引;否则你会看到性能非常缓慢。一些数据库产品会在你定义外键时自动创建这样的索引,但在某些情况下这样做并不有利,因此 PostgreSQL 将事情交给你来优化你认为合适的。 (举个例子,在正常操作期间维护索引可能不值得,但值得在清除之前构建它并在之后删除它。)

    【讨论】:

      【解决方案3】:

      请注意:ON DELETE CASCADE 在批量操作上表现不佳。原因是这是作为触发器完成的。因此,从算法的角度来看,它的外观是:

      for row in delete_set:
          for dependent row in (scan for referencing rows):
               delete dependent row
      

      如果您要删除父表中的 800000 行,这将转化为对从属表进行 800000 次单独的删除扫描。即使在最好的情况下,使用索引可用 800000 次单独的索引扫描也会比一次顺序扫描慢得多。

      更好的方法是在 9.1 或更高版本中使用可写的公用表表达式,或者只在同一事务中执行单独的删除语句。比如:

      WITH rows_to_delete (id) AS (
           SELECT id FROM mytable WHERE where_condition
      ),
      deleted_rows (id) AS (
           DELETE FROM referencing_table WHERE mytable_id IN (select id FROM rows_to_delete)
           RETURNING mytable_id
      ),
      DELETE FROM mytable WHERE id IN (select id FROM deleted_rows);
      

      这在算法上简化为:

      扫描要删除的行作为 delete_set 扫描依赖于删除的行: 删除依赖 对于 to_delete 扫描被删除的依赖项引用的行: 删除 to_delete

      摆脱强制嵌套循环扫描将大大加快速度。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-01-24
        • 2014-10-06
        • 2013-08-01
        • 2023-03-05
        • 2019-04-26
        • 1970-01-01
        • 1970-01-01
        • 2013-03-26
        相关资源
        最近更新 更多