简单查询导致 Django 中的内存泄漏

Posted

技术标签:

【中文标题】简单查询导致 Django 中的内存泄漏【英文标题】:Simple query causes memory leak in Django 【发布时间】:2019-08-26 14:10:58 【问题描述】:

我在一家拥有大型数据库的公司工作,我想对其执行一些更新查询,但这似乎会导致巨大的内存泄漏 查询如下

c= CallLog.objects.all()
for i in c:
   i.cdate = pytz.utc.localize(datetime.datetime.strptime(i.fixed_date, "%y-%m-%d %H:%M"))
   i.save()

我在 Django 的交互式 shell 中写了这个

我什至尝试使用

with transaction.atomic()

但它没有用,你知道我怎样才能检测到来源

我正在处理的数据集约为 2700 万

fixed_date 是一个计算属性

【问题讨论】:

为什么说是内存泄漏呢?运行此代码时发生了什么?您可以添加任何错误堆栈跟踪吗? 我有一台 4 GB 内存的机器,当我运行 htop 时,我看到所有内存都被 Django 吃掉了,然后系统冻结了 您需要使用 Redis 或某种队列处理程序来逐个处理所有数据 【参考方案1】:

你可以试试这样的:

from django.core.paginator import Paginator

p = Paginator(CallLog.objects.all().only('cdate'), 2000)
for page in range(1, p.num_pages + 1):
    for i in p.page(page).object_list:
        i.cdate = pytz.utc.localize(datetime.datetime.strptime(i.fixed_date, "%y-%m-%d %H:%M"))
        i.save()

对查询集进行切片并不只是为了获取子集而加载内存中的所有对象,而是在访问数据库之前为 SQL 查询添加限制和偏移量。

【讨论】:

我认为这段代码用相同的值更新了整个表,我想用它计算的 fixed_date 值更新每条记录。我考虑过 F() 表达式,但它不适用于计算属性 @AhmedIbrahim 我编辑了我的答案。试试这个,应该会好一点。如果这需要很长时间并且消耗内存,您应该考虑创建一个异步任务并让用户知道它何时完成。 我会试试这个然后回复你 它工作得很好,但速度很慢,但没关系,因为我只做一次【参考方案2】:

您可以尝试批量迭代查询集;请参阅.iterator() 方法。看看有没有什么改善

for obj in CallLog.objects.all():
    obj.cdate = pytz.utc.localize(
        datetime.datetime.strptime(obj.fixed_date, "%y-%m-%d %H:%M"))
    obj.save()

这是我找到的一个相关的answer,但它是几年前的。

【讨论】:

【参考方案3】:

试着把它分成小块(因为你只有 4gb 的内存)

c= CallLog.objects.filter(somefield=somevalue)

必要时,我通常使用字符或数字(ID 输入 1、2、3、4 等)

【讨论】:

以上是关于简单查询导致 Django 中的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

排查内存泄漏最简单和直观的方法

为啥使用“新”会导致内存泄漏?

WkWebView 实例化中的内存泄漏

是啥导致了netty中的这种内存泄漏

在循环中执行 Doctrine 查询时的内存泄漏

LeakCanary 内存泄漏 监测 性能优化 简介 原理