Django 1.2 PostgreSQL级联删除键,使用ON DELETE NO ACTION

时间:2011-09-06 15:14:44

标签: django postgresql cascading-deletes

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

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

使用Model.objects.filter().delete()不是一个选项,因为数据量巨大且需要花费大量时间。

只有sanest选项似乎是级联删除,但由于Django添加了“ON DELETE NO ACTION”,它似乎是一个无选择。

所以我的问题:有没有办法以简单的方式(有许多)或类似的东西将所有外键修改为ON DELETE CASCADE。

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

3 个答案:

答案 0 :(得分:1)

正如包含安德鲁答案的链接所指出的那样,如果你在Django中将其设置为CASCADE,那么Django将去删除“零售”。如果设置为NO ACTION,则可以创建数据库级外键定义来处理事物。这听起来像是一个合理的计划。

确保在每个外键的引用列上定义了索引;否则你会看到很慢的表现。当您定义外键时,某些数据库产品会自动创建这样的索引,但是在某些情况下这样做并不是有利的,因此PostgreSQL会根据您的需要将问题放在您的手中进行优化。 (正如一个例子,它可能不值得在正常操作期间维护索引的成本,但值得在清除之前构建它并在之后删除它。)

答案 1 :(得分:0)

答案 2 :(得分:0)

一个注意事项:ON DELETE CASCADE在批量操作上表现糟糕。原因是这是作为触发器完成的。因此,从算法的角度看它的样子是:

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

如果要删除父表中的800000行,则转换为依赖表上的800000个单独的删除扫描。即使在最好的情况下,索引可用800000个单独的索引扫描也会比一个顺序扫描慢得多。

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

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    依赖于扫描依赖于删除的行:        删除依赖    for to_delete in scan for deleted dependents引用的行:         删除to_delete

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