【问题标题】:Django N+1 query solutionDjango N+1 查询解决方案
【发布时间】:2011-07-22 06:52:52
【问题描述】:

在与同行讨论 N+1 以及不良数据库查询对性能的严重影响后,我访问了 http://guides.rubyonrails.org/active_record_querying.html

ActiveRecord (Rails):

clients = Client.includes(:address).limit(10)

如果客户端有地址,并且我打算在遍历客户端时访问它们,Rails 会提供includes 让它知道继续并将它们添加到查询中,这样一来就消除了 9 个查询。

姜戈:

https://github.com/lilspikey/django-batch-select 提供批量查询支持。您是否知道其他库或技巧来实现 Rails 提供的上述功能,但不那么冗长(如在 rails 示例中,其中只有 19 个字符修复 N+1 并且非常清楚)?另外,批量选择是否以相同的方式解决了这个问题,还是这两个不同的东西?

顺便说一句,我问的不是select_related,尽管乍一看它似乎是答案。我说的是address 有一个指向client 的外键的情况。

【问题讨论】:

    标签: django django-orm select-n-plus-1


    【解决方案1】:

    不幸的是,到目前为止,Django 的 ORM 还没有办法做到这一点。

    幸运的是,只需 2 次查询就可以做到这一点,并在 Python 中完成了一些工作。

    clients = list(Client.objects.all()[:10])
    addresses = dict((x.client_id, x) for x in
        Address.objects.filter(client__in=clients))
    for client in clients:
      print client, addresses[client.id]
    

    【讨论】:

    • 谢谢。顺便说一句,这会创建一个高效的查询(即,Rails 是否可能做任何神奇的事情来提供更好的性能,或者他们的可能只是同一件事的语法糖)?显然,如果不必立即对所有内容进行评估记忆会更好,但也许他们也正在这样做。
    • 我不知道。 可以在一个查询中执行该操作,但这需要 Django 的 ORM 尚不具备的技巧。
    【解决方案2】:

    django-batch-select 应该可以解决这个问题,虽然我还没有尝试过。上面伊格纳西奥的回答对我来说似乎是最好的。

    【讨论】:

      【解决方案3】:

      自 Django 1.4 起,您可以使用 prefetch_related 来做到这一点: https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related

      如果您使用的是 https://github.com/ionelmc/django-prefetch

      它声称比 Django 的 prefetch_related 更灵活。冗长但效果很好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-03-22
        • 2015-11-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多