Django N + 1查询解决方案

时间:2011-03-24 16:14:27

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

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

ActiveRecord(Rails):

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

如果客户端有地址,并且我打算在循环访问客户端时访问它们,Rails提供includes让它知道继续并将它们添加到查询中,这样可以立即消除9个查询。

Django的:

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

顺便说一下,我不是在问select_related,虽然乍一看似乎是答案。我说的是address有一个client的forign键的情况。

3 个答案:

答案 0 :(得分:12)

你可以使用prefetch_related从Django 1.4开始: https://docs.djangoproject.com/en/dev/ref/models/querysets/#prefetch-related

如果您正在使用< 1.4,看看这个模块:  https://github.com/ionelmc/django-prefetch

它声称比Django的prefetch_related更灵活。详细但很有效。

答案 1 :(得分:9)

不幸的是,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]

答案 2 :(得分:2)

django-batch-select应该提供这个问题的答案,尽管我还没有尝试过。伊格纳西奥的答案对我来说似乎最好。