【发布时间】:2014-09-01 16:00:58
【问题描述】:
有没有办法告诉prefetch_related 只获取一组有限的相关对象?假设我正在获取用户列表,并且我知道我想获取他们最近的 cmets。我没有在循环中为每个用户获取 cmets,而是使用 prefetch_related 在获取用户时预取它们。我的理解是,这将获取原始查询结果中存在的任何用户创建的所有 cmets,但我只想为每个用户显示最新的 5 个。
如果 cmets 列表真的很大,这会如何影响性能?有没有办法在单个(或 2 个)查询中为每个用户仅获取 5 个 cmets?它不必与用于获取用户的原始查询相同,但这很好。
我本质上是想转这个
users = User.objects.all()
for user in users:
user.comments.all()[:10]
变成这样的
User.objects.all().prefetch_related('comments', limit=10)
因此,如果用户有 100 或 10000 个 cmets,它们不会全部加载到内存中。你会如何在原始 SQL 中做这样的事情?
【问题讨论】:
-
我不认为使用预取是做这件事的好方法。事实上 prefetch_related 对每个关系进行单独的查找,并在 Python 中进行连接。这意味着您将在 python 中预加载 cmets,并且连接将从这个预加载的 cmets 列表中完成。在您的情况下,为了确保每个用户的最后 10 个 cmets,您需要预加载所有这些用户
-
我可以忍受每个关系一个查询,但每个对象一个查询才是真正的杀手。
-
我同意,每个对象一个查询是一场噩梦。但是为什么不直接做:
users = User.objects.all().prefetch_related('comments')在这种情况下,您将只执行 2 个查询 -
如果 cmets 表有数十万行与选中的用户相关联怎么办?用户评论关系不太可能出现,但在其他情况下很有可能。我担心为您选择的每 10 到 20 个用户(考虑分页)获取所有数百或数千个 cmets 并将它们加入 python 会出现性能问题。
-
在这种情况下,我最好的办法可能是在 redis 之类的东西中缓存排名靠前的 commet,或者对排名前 10 的 cmets 进行非规范化。
标签: sql django postgresql