讲师中心 微信公众号
AI工具推荐 视频效率加速

如何在Python Django 4.2中优化慢查询_使用select_related与prefetch_related

陌婷小哥_3429

陌婷小哥_3429

发布时间:2026-05-27 06:17:47

|

234人浏览过

|

来源于php中文网

原创

select_related 仅适用于 ForeignKey 和 OneToOneField,通过 JOIN 优化单值关联;prefetch_related 用于多值关联(如 ManyToManyField、反向关系),通过额外查询+Python归组实现优化;二者必须在 QuerySet 构建阶段正确选用,否则无效甚至恶化性能。

如何在python django 4.2中优化慢查询_使用select_related与prefetch_related

直接说结论:select_related 和 prefetch_related 不是“用了就快”,而是必须匹配关联类型、访问模式和数据规模才真正生效;用错一个,不仅没优化,还可能让查询更慢、内存更高、甚至报错。

什么时候该用 select_related 而不是 prefetch_related

select_related 只对单值关系有效:即 ForeignKey(正向)和 OneToOneField。它靠 SQL 的 LEFT OUTER JOIN 一次性把关联表字段拉回来。

  • ✅ 正确场景:查 Order 列表时要显示每个订单的 user.username 和 user.company.name —— 全是外键链,写成 Order.objects.select_related("user__company")
  • ❌ 错误场景:想查 Post 的所有 tags(ManyToManyField)或 post.comment_set.all()(反向多对一),select_related("tags") 会直接抛 FieldError
  • ⚠️ 注意 NULL:JOIN 后字段可能为 NULL,比如 user.profile 不存在时,obj.user.profile.bio 会报 AttributeError,得先判空
  • ⚠️ 嵌套深度有硬限制:MySQL 默认最多 JOIN 61 张表,"a__b__c__d__e__f__g" 这种七层嵌套在某些部署环境下会触发 ERROR 1116 (HY000): Too many tables

什么时候必须换用 prefetch_related

prefetch_related 是为集合关系设计的:反向多对一(如 user.order_set)、多对多(如 post.tags)、自定义 related_name 的任意集合字段。它发额外查询 + Python 层归组,不走 JOIN。

  • ✅ 正确场景:展示文章列表时要渲染每篇的 tags.all 和 comments.count,写成 Post.objects.prefetch_related("tags", "comment_set")
  • ❌ 白跑情况:只写了 prefetch_related("comments"),但在视图里没调 post.comments.all() 或 len(post.comments.all()) —— 预取根本不会触发
  • ⚠️ 不能混用同一字段:比如已 select_related("author"),再加 prefetch_related("author__profile"),Django 会静默忽略后者
  • ⚠️ values() 会废掉所有预取:一旦调用 .values("title", "author_id"),后续访问 obj.author.name 就又变 N+1 —— 因为返回的是字典,不是模型实例

模板和序列化里最容易漏掉的 N+1

N+1 很少出现在 view 函数的 for 循环里,更多藏在 DRF 序列化器或 Django 模板中,而且你根本看不到 SQL 发起点。

361SCAN security check your skill python scripts
361SCAN security check your skill python scripts

扫描并分析已安装技能,用于查看指定技能目录的名称、描述和详情,或列出所有已安装的技能。

下载

立即学习“Python免费学习笔记(深入)”;

  • DRF 的 SerializerMethodField:如果方法里写了 obj.author.name,但 QuerySet 没 select_related("author"),每个对象都会单独查一次 author
  • 模板中 {{ post.author.name }} 看似简单,但若 post 是从 Post.objects.all() 来的,就是典型 N+1
  • 反向关系名必须严格匹配:prefetch_related("comment_set") 有效,但模板里写 {% for c in post.comments.all %} 就失效——除非模型定义了 related_name="comments"
  • count() 是查询,不是属性缓存:哪怕用了 prefetch_related("comments"),post.comments.count() 仍会发新 SQL,应改用 post.comments.all().count()(已预取)或提前注解 .annotate(comments_count=Count("comments"))

性能权衡:JOIN 快还是两次查询快?

没有银弹。JOIN 并不总是更快——尤其当关联表行数远超主表、或你只用关联表一两个字段时,select_related 可能导致结果集膨胀、传输变慢、内存飙升。

  • 主表 100 行 × 关联表平均 50 行 → JOIN 后传 5000 行数据,而 prefetch_related 只传 100 + 50 = 150 行,明显后者更轻量
  • 你要排序或过滤关联字段(如 .order_by("user__last_login")),select_related 更合适;但若要按关联表聚合(如 .annotate(avg_rating=Avg("review__score"))),JOIN 可能生成低效 SQL,此时先 prefetch_related 再 Python 计算反而更稳
  • 别跳过基础优化:索引比任何 ORM 技巧都重要。没给 user_id 加索引,select_related("user") 再快也卡在 JOIN 扫表上

最常被忽略的一点:这两个方法都依赖 QuerySet 的惰性求值。一旦你调了 list()、len()、[0]、或者在模板里用了 {% for %},QuerySet 就执行了——之后再链式加 select_related 完全无效。优化必须写在 QuerySet 构建阶段,而不是数据拿到手之后补救。

热门AI工具

更多
音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

1771

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

4584

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

1729

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

27117

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

3287

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

3287

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

1203

2023.08.11

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

596

2023.08.10

OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

80

2026.10.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Uvicorn官方安装与入门手册
Uvicorn官方安装与入门手册

共0课时 | 0人学习

Python uv官方项目管理指南
Python uv官方项目管理指南

共0课时 | 0人学习

Python uv官方安装与入门文档
Python uv官方安装与入门文档

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn