当前位置:

首页 > 编程开发 > Django 6.1 RC1 实测:FETCH_PEERS 两条 SQL 解决 N+1,select_related 还需要吗?

Django 6.1 RC1 实测:FETCH_PEERS 两条 SQL 解决 N+1,select_related 还需要吗?

Django 6.1 RC1 实测:FETCH_PEERS 两条 SQL 解决 N+1,select_related 还需要吗? Django 6.1 RC1 在 2026 年 7 月 22 日发布,正式版已进入最后的发布窗口。这个版本最值得后端开发者关注的变化之一,是 ORM 新增了 Fetch

本文目录

    Django 6.1 RC1 实测:FETCH_PEERS 两条 SQL 解决 N+1,select_related 还需要吗?

    Django 6.1 RC1 在 2026 年 7 月 22 日发布,正式版已进入最后的发布窗口。这个版本最值得后端开发者关注的变化之一,是 ORM 新增了 Fetch Modes(字段获取模式)。

    它试图解决一个老问题:代码运行时才访问关联字段,开发者又没有提前写 select_related() 或 prefetch_related(),于是一次列表查询悄悄膨胀成 N+1 条 SQL。

    这篇文章不只介绍 API。我在隔离环境中安装了 Django 6.1 RC1,用 100 本书和 100 位作者做了一次可复现实验,直接比较:

    • 默认的 FETCH_ONE;
    • 新增的 FETCH_PEERS;
    • 传统的 select_related();
    • 用来阻止意外查询的 RAISE。

    先给结论:FETCH_PEERS 很有价值,但它不是 select_related() 的替代品。

    N+1 为什么总在代码评审后才暴露

    假设每本书都关联一位作者:

     复制代码class Author(models.Model):
        name = models.CharField(max_length=100)
    class Book(models.Model):
        title = models.CharField(max_length=200)
        author = models.ForeignKey(Author, on_delete=models.CASCADE)
    

    下面的代码看起来非常自然:

     复制代码books = Book.objects.all()for book in books:
        print(book.author.name)
    

    第一条 SQL 查询 100 本书。之后,每次访问 book.author,Django 都需要再查询一次作者,于是总数变成:

     复制代码1 条 Book 查询 + 100 条 Author 查询 = 101 条 SQL
    

    传统修复方式是提前声明关联字段:

     复制代码books = Book.objects.select_related("author")
    

    它会使用 JOIN,一条 SQL 就把书和作者一起取回。问题在于,真实系统中的字段访问经常由序列化器、模板、插件或运行时分支决定,写查询的人未必知道后面会访问哪个字段。

    这正是 FETCH_PEERS 想补上的空白。

    Django 6.1 的三种 Fetch Mode

    FETCH_ONE:保持原来的行为

     复制代码from django.db import modelsbooks = Book.objects.fetch_mode(models.FETCH_ONE)
    

    当一个未加载字段被访问时,只为当前对象取一次数据。这是 Django 过去的行为,也是 Django 6.1 的默认模式。

    优点是行为稳定、单次访问成本明确;缺点是放进循环后很容易形成 N+1。

    FETCH_PEERS:第一次访问时批量补齐同批对象

     复制代码books = Book.objects.fetch_mode(models.FETCH_PEERS)for book in books:
        print(book.author.name)
    

    第一次访问某一本书的 author 时,Django 会找到来自同一个 QuerySet 的其他 Book 实例,并批量获取它们需要的关联作者。最终查询形态通常是:

    1. 查询全部 Book;
    2. 批量查询这些 Book 对应的 Author。

    它很像“按需触发的 prefetch_related()”:只有代码真正访问关联字段时,第二条查询才发生。

    RAISE:不允许代码偷偷访问数据库

     复制代码books = Book.objects.fetch_mode(models.RAISE)for book in books:
        print(book.author.name)
    

    一旦 author 未能提前加载,Django 便不再默默执行查询,而是直接抛出 FieldFetchBlocked 异常。这一机制在性能敏感场景、模板渲染及 API 序列化测试中显得尤为关键:它让意外产生的 SQL 无法再悄无声息地溜过,而是立刻报错,从而确保代码行为的确定性。

    100 本书的真实查询结果

    测试环境如下:

    项目配置
    Django6.1 RC1
    Python3.12
    数据库SQLite 内存数据库
    数据量100 Author + 100 Book
    关系每本书关联一位作者
    计数方法connection.queries

    核心测试函数只有几行:

     复制代码def measure(label, queryset):
        connection.queries_log.clear()
        started = perf_counter()
        books = list(queryset)
        names = [book.author.name for book in books]
        elapsed_ms = (perf_counter() - started) * 1000
        print(label, len(connection.queries), elapsed_ms)
    

    四种模式依次运行:

     复制代码measure("FETCH_ONE", Book.objects.fetch_mode(models.FETCH_ONE))
    measure("FETCH_PEERS", Book.objects.fetch_mode(models.FETCH_PEERS))
    measure("select_related", Book.objects.select_related("author"))blocked = list(Book.objects.fetch_mode(models.RAISE))
    print(blocked[0].author.name)  # FieldFetchBlocked
    

    本机单次结果如下:

    策略SQL 数量单次耗时
    FETCH_ONE10123.74 ms
    FETCH_PEERS23.09 ms
    select_related11.26 ms
    RAISE阻止查询抛出 FieldFetchBlocked

    这组数据更适合用来说明查询形态,本身并不能直接当作通用性能排行榜来看。原因很简单:SQLite 的内存数据库、数据规模、字段宽度、网络延迟,甚至数据库执行计划,都会把最终耗时拉向不同结果。真正更稳、更有参考价值的结论,其实是 SQL 的数量变化——在这个关系访问场景里,FETCH_PEERS 直接把 101 条 SQL 压缩到了 2 条。

    select_related 还需要吗?当然需要

    如果业务代码明确知道“这次一定会访问作者”,select_related("author") 仍然是最直接的表达:

     复制代码books = Book.objects.select_related("author")
    

    它的优势有三个:

    1. 查询意图在代码中清晰可见;
    2. 只执行一次 JOIN;
    3. 不需要等到第一次属性访问时才触发第二条 SQL。

    FETCH_PEERS 更适合访问路径不确定的场景。例如:

    • 同一个 QuerySet 被多个序列化器复用;
    • 模板根据权限决定是否展示关联字段;
    • 插件或扩展在运行时访问模型属性;
    • 希望减少 N+1,又不想为每条动态路径维护预取字段列表。

    换句话说,select_related() 是“我明确知道会用什么”;FETCH_PEERS 是“我运行到这里才知道需要什么,但请不要逐条查询”。

    一张图完成策略选择

    可以把选型压缩成三条规则:

    规则一:字段明确且必用,优先 select_related

    对于 ForeignKey 和 OneToOneField,如果调用链明确,JOIN 通常更直接。

    规则二:访问由运行时决定,考虑 FETCH_PEERS

    它能在真正访问字段时批量补齐同一 QuerySet 的对象,避免逐条获取。

    规则三:性能边界必须严格,使用 RAISE

    把隐式查询变成测试失败,尤其适合高吞吐 API、循环和模板渲染边界。

    FETCH_PEERS 的边界不能忽略

    第一,它只影响未加载字段和关联对象的获取行为,不会让任意 ORM 查询自动变快。

    第二,它不是数据库缓存。第二条批量查询仍然真实发生,只是从 N 条缩减为一条。

    第三,模式会沿着获取到的关联对象继续传播。复杂关系树中应观察真实 SQL,而不是凭感觉判断。

    第四,Django 6.1 RC1 仍是预发布版本。正式版发布前,API 与边界行为仍应以最终文档和发布说明为准,生产环境不要因为一篇基准文章直接升级。

    升级前的验证清单

    • 在隔离环境安装 Django 6.1 RC1,不直接修改生产依赖;
    • 为关键列表接口记录 SQL 数量基线;
    • 对已知字段继续使用 select_related() / prefetch_related();
    • 在动态访问路径试用 FETCH_PEERS;
    • 在不允许隐式查询的测试中启用 RAISE;
    • 同时比较 SQL 数量、返回数据量和数据库执行计划;
    • 检查第三方包是否支持 Django 6.1;
    • 正式升级前重新阅读最终版 6.1 发布说明。

    结论:FETCH_PEERS 是新工具,不是万能替代

    Django 6.1 没有宣布 select_related() 过时。它新增的是一套更细的控制手段:

    • FETCH_ONE 保留兼容行为;
    • FETCH_PEERS 在运行时批量补齐同批对象;
    • RAISE 把意外 SQL 变成明确错误;
    • select_related() 继续负责已知关系的主动 JOIN。

    真正值得升级的不是“少写一个 select_related”,而是 ORM 第一次允许我们明确表达:缺失字段应该单独取、成批取,还是根本不许取。

    如果你的项目中既有 DRF 序列化器又有复杂模板,你更希望先在哪一层尝试 FETCH_PEERS?

    参考资料

    • Django 6.1 RC1 发布公告
    • Django 6.1 Fetch Modes 官方文档
    • Django 6.1 发布说明
    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    如何正确遍历 PDO::FETCH_ASSOC 返回的二维关联数组
    如何正确遍历 PDO::FETCH_ASSOC 返回的二维关联数组

    使用PDO的fetchAll(PDO::FETCH_ASSOC)方法返回二维关联数组,若直接遍历输出会引发“Arraytostringconversion”错误。正确做法是采用两层循环:外层遍历每条记录,内层遍历键值对,逐层解构数据,避免错误。

    Vue项目开发中的数据请求与处理经验
    Vue项目开发中的数据请求与处理经验

    在Vue项目开发中,数据请求与处理是非常重要的环节。一个好的数据请求与处理策略可以大大提高应用的性能和用户体验。本文将分享一些在Vue项目开发中的数据请求与处理的经验。合理使用Axios库Axios是一个常用的基于Promise的HTTP库,用于发送XHR请求。在Vue项目中,可以使用Axios来发送数据请求。在使用Axios时,需要注意以下几点:合理配置A

    thinkphp fetch方法怎么用
    thinkphp fetch方法怎么用

    首先,fetch方法是ThinkPHP框架中的一个渲染方法,这个方法主要用来加载视图页面并进行渲染。这个方法在ThinkPHP框架的View类中定义,因此,我们需要先找到View类。View类在ThinkPHP框架中的路径如下:thinkphp/library/think/View.php我们可以通过这个路径找到View类所在的源代码文件。打开View.php源文件,我们可以看到View类中定义了fetch()方法,它的代码如下:/***渲染模板输出*@acces

    如何使用ThinkPHP中的fetch方法获取数据?
    如何使用ThinkPHP中的fetch方法获取数据?

    在thinkphp中,fetch方法用于渲染模板文件输出,该方法不会直接渲染输出,而是支持模板或者内容的标签解析,返回解析后的内容,渲染输出系统也会自动调用send方法进行渲染输出,语法为“$this->fetch(模板名称);”。本文操作环境:Windows10系统、ThinkPHP3.2版、DellG3电脑。thinkphp中fetch方法怎么用实例化视图类5.0模板渲染提供了fetch和display两个方法,最常用的是fetchfetch方法用于渲染模板文件输出,

    Cursor新增实时语音对话:可边通话边让Agent编程
    Cursor新增实时语音对话:可边通话边让Agent编程

    Cursor新增实时语音对话,支持在Agent运行任务时交流并听取进度,覆盖Agents Window、IDE、网页端与iOS,语音通话需登录账号并开启麦克风权限。

    VS Code 1.145更新:Cron调度、远程预览与补丁修复
    VS Code 1.145更新:Cron调度、远程预览与补丁修复

    VS Code 1.145新增本地Cron调度,扩展远程Agent预览能力;后续1.145.1与1.145.2修正遥测归属和事件路由。文中区分正式、预览及实验性功能。

    Ponytail适用人群与使用场景解析
    Ponytail适用人群与使用场景解析

    Ponytail面向已使用AI编程助手并希望优化代码质量的开发者,以及负责维护旧项目或审查AI生成代码的技术人员。它提供了一套可重复加载的开发判断规则,帮助用户减少冗余代码、梳理数据流并评估技术选型。虽然非编程人员也可提出任务,但仍需具备一定技术判断力来核对兼容性、行为逻辑及必要检查项。本文详解其在代码审查、旧项目维护及前端原生能力评估中的具体应用路径。

    Impeccable安装后命令无法使用排查指南
    Impeccable安装后命令无法使用排查指南

    面向在Cursor或Codex中配置Impeccable技能的用户,解决安装后命令无法调用、菜单不显示或钩子无响应的问题。本文梳理从终端环境检查到工具重载的完整路径:确认Node.js与PATH配置,区分npx终端命令与聊天助手指令(如/impeccable audit),通过/impeccable check和update管理版本,利用/impeccable doctor修复配置漂移,并单独核对/hooks状态以排除权限干扰,避免盲目重装导致配置覆盖。

    DeepSeek SuperAgent非程序员使用指南:门槛与协作建议
    DeepSeek SuperAgent非程序员使用指南:门槛与协作建议

    面向希望利用 DeepSeek SuperAgent 辅助开发但缺乏编程背景的用户,本文解析其实际使用门槛。虽然任务派发可通过自然语言完成,适合业务人员整理需求,但独立部署、环境配置及代码审阅仍需技术基础。文章说明安装时的账号权限管理要点,指导如何通过面板监控任务状态,并强调在无人负责技术维护时不宜盲目自动化,需由专业人员验收代码以确保安全。

    Ponytail在Claude Code中的用途:控制代码规模、审查改动与整理技术债务
    Ponytail在Claude Code中的用途:控制代码规模、审查改动与整理技术债务

    面向使用Claude Code进行开发的程序员,Ponytail插件旨在通过引导AI助手优先复用现有能力来控制新增代码规模。本文介绍其核心用途:在开发任务中减少不必要代码编写,通过“/ponytail-review”命令审查暂存改动的安全性与可维护性,以及利用“/ponytail-debt”整理带有明确限制的开发捷径和技术债务。使用前需根据安装方式确认宿主支持的具体命令和自动加载功能。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。