2011-09-06 63 views
4

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

现在我需要批量从一堆基于某些条件表的删除数据(约80万条记录)。

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

只有sanest选项似乎级联删除,但由于Django的有添加“ON DELETE NO ACTION”它看起来像一个没有选择。

所以我的问题:有没有办法改变这一切foreing键在一个简单的方法DELETE CASCADE(其中还有不少的),或者类似的东西。

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

回答

1

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

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

0

一个注释:ON DELETE CASCADE在批量操作。原因是这是作为触发器完成的。因此它看起来从算法的角度来看,方法是:

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

如果要删除这个转化父表中的80万行成的从属表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 的依赖性扫描依赖于删除行: 删除依赖 为to_delete在扫描的行通过删除家属引用: 删除to_delete

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