如何减少查询次数?

Ada*_*ver 7 python django

此代码当前正在执行大约50个SQL查询:

c = Category.objects.all()

categories_w_rand_books = []

for category in c:
    r = Book.objects.filter(author__category=category).order_by('?')[:5]

    categories_w_rand_books.append((category, r))
Run Code Online (Sandbox Code Playgroud)

我需要将使用过的查询数量减少到最低,以加快速度并且不会导致服务器负载.

基本上,我有三个模型:类别,作者,书.作者属于类别(不是书籍),我需要获得所有类别的列表,每个类别下有5本随机书籍.

okm*_*okm 2

如果您更喜欢单个查询并且正在使用MySQL,请查看@Crazyshezy 在他的评论中提供的优秀链接
对于后端,可能的查询是(假设从to和 from toPostgreSQL存在不可为空的FK关系):BookAuthorAuthorCategory

SELECT * FROM (
    SELECT book_table.*, row_number() OVER (PARTITION BY category_id ORDER BY RANDOM()) AS rn 
    FROM book_table INNER JOIN author_table ON book_table.author_id = author_table.id
) AS sq 
WHERE rn <= 5 
Run Code Online (Sandbox Code Playgroud)

然后你可以将它包装在 a 中RawQuerySet来获取Book实例

from collections import defaultdict
qs = Book.objects.raw("""The above sql suited for your tables...""")
collection = defaultdict(list)
for obj in qs:
    collection[obj.category_id].append(obj)

categories_w_rand_books = []
for category in c:
    categories_w_rand_books.append((category, collection[category.id]))
Run Code Online (Sandbox Code Playgroud)

您可能不想在没有一些缓存的情况下直接为每个请求运行此查询。

此外,您的代码最多随机生成 50*5=250Book秒,我只是想知道为什么,因为对于单个页面来说似乎太多了。项目是否显示为选项卡或其他形式?也许您可以通过使用 Ajax 来减少 SQL 的数量,或者简化需求?

更新

要使用book.author不触发多个其他查询,请尝试prefetch_related_objects

from django.db.models.query import prefetch_related_objects
qs = list(qs) # have to evaluate at first
prefetch_related_objects(qs, ['author'])
# now instances inside qs already contain cached author instances, and
qs[0].author # will not trigger an extra query
Run Code Online (Sandbox Code Playgroud)

上面的代码批量预取作者并将其填充到qs. 这只是添加了另一个查询。