【问题标题】:Get million record from django with queryset is slow使用查询集从 django 获取百万记录很慢
【发布时间】:2017-04-21 10:26:45
【问题描述】:

我想迭代一个表的所有对象(Post) 我正在使用以下代码:

posts = Post.objects.all()
for post in posts:
   process_post(post)

process_post 是一项 celery 任务,它将在后台运行并且不会更新帖子。但我遇到的问题是 Post 表有 100 万条记录。这不是一次性工作。我每天都在运行它。

for post in posts

在上面一行中,调用了 Query,它一次性从 DB 中获取所有数据。

如何提高其性能? 有什么方法可以批量获取数据吗?

【问题讨论】:

  • process_post 是更新方法吗?
  • 使用iterator()。如果它仍然导致过多的内存消耗,您可能需要考虑使用数据库端游标。
  • 数据由 Django 批量获取的。实际上,默认行为是加载所有内容。但是将行加载为 python 对象是一个缓慢的过程,如果你只有简单的处理,我建议你使用values()update(),如果可能的话甚至单独使用update()。 ...并使其处理自定义管理器或查询集方法。
  • select_related() 和 prefetch_related() 对我优化 django 查询非常有用。这篇文章可能会有所帮助:bookofstranger.com/…
  • @Surajano process_post 是一个 celery 任务,它将在后台运行并且不会更新帖子

标签: python django postgresql


【解决方案1】:

制作您自己的iterator。例如,说1 million 记录。

count = Post.objects.all().count() #1 million
chunk_size = 1000   
for i in range(0, count, chunk_size):
    posts = Post.objects.all()[i:i+chunk_size]
    for post in posts:
        process_post(post)        

在查询集上切片将播放LIMITOFFSET 用法。查询可以随着chunk_size 的增加而减少,而内存使用量也会增加。针对您的用例进行优化。

【讨论】:

    【解决方案2】:

    我的第一个建议是使用 select_related 或 prefetch_related。浏览 django 的文档并了解它,它应该可以解决您的问题。但是正如您所说,该表有数百万条记录。遍历这些将始终是一项昂贵的业务。如果 process_post 方法需要时间,最好的解决方案是使用存储过程。您只需向您的数据库发出一个请求即可实现您的目标,而不是循环中的数百万次数据库调用。

    【讨论】:

      【解决方案3】:

      Django 不用于处理数据。这只是为前端制作 API 和 ORM 的框架。

      你可以根据你的内存和数据库来限制进程,比如 obj = post.objects.all()[30000] 等或 50000

      如果你想在 HTML 前端显示,请使用分页

      如果你想在后端处理,不要使用 Django ORM。在数据库中制作实体化视图和数据库作业(这在 oracle 数据库中非常容易)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-04-12
        • 2020-05-31
        • 1970-01-01
        • 1970-01-01
        • 2015-12-14
        • 2019-02-28
        • 1970-01-01
        • 2021-03-27
        相关资源
        最近更新 更多