使用`delete()`时如何防止django在内存中加载对象?

时间:2015-07-17 14:05:14

标签: sql django django-models

我有内存问题,因为看起来Django在使用delete()时正在将对象加载到内存中。有没有办法阻止Django这样做?

来自Django文档:

  

Django需要将对象提取到内存中以发送信号和处理级联。但是,如果没有级联和没有信号,那么Django可能会采用快速路径并删除对象而不会进入内存。对于大型删除,这可能会导致内存使用量大幅减少。执行查询的数量也可以减少。

https://docs.djangoproject.com/en/1.8/ref/models/querysets/#delete

我没有使用信号。我确实在我试图删除的模型上有外键,但我不明白为什么Django需要将对象加载到内存中。看起来确实如此,因为查询运行时我的内存正在上升。

2 个答案:

答案 0 :(得分:4)

你可以使用这样的函数迭代大量的对象,而不需要使用太多的内存:

import gc

def queryset_iterator(qs, batchsize = 500, gc_collect = True):
    iterator = qs.values_list('pk', flat=True).order_by('pk').distinct().iterator()
    eof = False
    while not eof:
        primary_key_buffer = []
        try:
            while len(primary_key_buffer) < batchsize:
                primary_key_buffer.append(iterator.next())
        except StopIteration:
            eof = True
        for obj in qs.filter(pk__in=primary_key_buffer).order_by('pk').iterator():
            yield obj
        if gc_collect:
            gc.collect()

然后您可以使用该函数迭代要删除的对象:

for obj in queryset_iterator(HugeQueryset.objects.all()):
    obj.delete()

有关详细信息,请查看this blog post

答案 1 :(得分:0)

您可以导入django数据库连接并将其与sql一起使用来删除。我遇到了和你一样的问题,这对我有很大帮助。这里有一些片段(我顺便使用mysql,但你可以运行任何sql语句):

from django.db import connection
sql_query = "DELETE FROM usage WHERE date < '%s' ORDER BY date" % date
cursor = connection.cursor()
try:
    cursor.execute(sql_query)
finally:
    c.close()

这应该只对该表执行删除操作,而不会影响任何模型关系。