You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Django ORM查询关联表中每本书对应的最后50名作者数据

Django ORM 分组取每组前N条性能优化方案

你当前的写法属于典型的N+1查询问题:首先执行1次查询获取所有Book数据,之后每遍历1本图书都会单独发起1次SQL查询获取对应的作者数据,当图书数量较多时会产生大量数据库请求,导致性能极差。

优化方案1:使用Prefetch自定义关联查询(Django 2.0+ 推荐,改动最小)

利用Django内置的Prefetch对象可以自定义关联查询的过滤、排序、切片规则,仅用2次SQL查询就能拿到所有需要的数据,不会产生额外请求。
代码示例:

from django.db.models import Prefetch

# 预查询每本书的最新50名作者,自定义关联字段名为latest_50_authors
books = Book.objects.prefetch_related(
    Prefetch(
        'author_set', 
        # 这里的排序规则根据你对"最后50名"的定义调整,示例按主键倒序即最新插入的50条
        queryset=Author.objects.order_by('-id')[:50], 
        to_attr='latest_50_authors'
    )
).all()

# 遍历逻辑
for book in books:
    for author in book.latest_50_authors:
        # 你的业务逻辑
        pass

优化方案2:窗口函数实现(超大数据量场景推荐,性能最优)

如果你的图书总量非常大,想要更极致的查询性能,可以使用窗口函数先给作者按所属图书分组排序打行号,过滤出行号≤50的作者,仅需2次查询就能拿到全量数据,内存开销也更低。
代码示例:

from django.db.models import F, Window
from django.db.models.functions import RowNumber

# 给每个作者按所属图书分组,按倒序排列后标记行号,只保留每组前50条
authors = Author.objects.annotate(
    row_num=Window(
        expression=RowNumber(),
        partition_by=F('book_id'),
        # 排序规则可根据业务调整,示例按主键倒序
        order_by=F('id').desc()
    )
).filter(row_num__lte=50).select_related('book')

# 组装成图书对应作者的映射结构
book_author_map = {}
for author in authors:
    book = author.book
    if book.id not in book_author_map:
        book_author_map[book.id] = {
            "book": book,
            "authors": []
        }
    book_author_map[book.id]["authors"].append(author)

# 遍历逻辑
for item in book_author_map.values():
    book = item["book"]
    for author in item["authors"]:
        # 你的业务逻辑
        pass

内容的提问来源于stack exchange,提问作者Dima

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 23:36:08