我有一个Django模型,其表中有数百万条记录。我正在尝试对shell中表中的所有记录进行一些紧急维护,但是如果没有完全耗尽系统中的内存,我将无法执行MyModel.objects.all()
。
即使是pass
也会导致OOM杀手被调用,从而导致我的进程被终止:
for ii in MyModel.objects.all():
pass
原因是因为Django的QuerySet
正在尝试建立一个“结果缓存”,通过在其中构建一个包含所有记录的列表,在这里:
# django/db/models/query.py
def _fetch_all(self):
if self._result_cache is None:
self._result_cache = list(self.iterator()) # <<<< this guy!
if self._prefetch_related_lookups and not self._prefetch_done:
self._prefetch_related_objects()
但我的机器无法将整个列表保存在内存中。
当然,在这么大的表上迭代.all()
在真实的应用程序中会是一个糟糕的想法,所以这个问题的范围相当有限(维护活动),但确实会不时出现。
答案 0 :(得分:4)
首先要尝试的是在迭代之前在查询集上使用iterator()
方法:
for ii in MyModel.objects.all().iterator():
答案 1 :(得分:0)
您可能无法将所有完整记录放入内存中,但很有可能您可以将所有主键放入内存中。因此,您可以迭代所有主键的列表,并在每个主键上执行bar
并单独操作记录:
public static void main(String[] args) {
LocalDate today = LocalDate.now();
System.out.println("Current date: " + today);
//add 1 week to the current date
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("Next week: " + nextWeek);
}
当然,这不是超级CPU效率,但它的内存效率更高。鉴于此类事情应仅用于维护活动,不太理想的性能有望成为问题。
答案 2 :(得分:0)
如果您使用的是python3.X,可以尝试一些异步任务。
创建计划提取可能很有用。
这样的事情:
async def _fetch_all(self):
if self._result_cache is None:
self._result_cache = await list(self.iterator()) # <<<< this guy!
if self._prefetch_related_lookups and not self._prefetch_done:
await self._prefetch_related_objects()
运行代码:
import asyncio
my_model = MyModel()
asyncio.get_event_loop().run_until_complete(my_model._fetch_all())
但如果您使用的是2.7,则需要使用celery创建异步任务或尝试使用某些工具来执行此操作,如Django Async。
希望它有所帮助。
答案 3 :(得分:0)
正确的答案是在迭代之前在查询集上使用Django的iterator()
方法。但是,您还必须将查询包装在事务中。
with transaction.atomic():
for ii in MyModel.objects.all().iterator():
这是因为默认情况下,Django在“自动提交”模式下运行,这意味着数据库游标将具有WITH HOLD
参数,从而导致常见的数据库(如postgres)使用较大的临时文件。