当前位置: 首页 > news >正文

Django `select_related` 查询优化

目标

  • 理解 N+1 查询问题及其性能影响
  • 掌握 select_related 的作用和使用方法
  • 能够分析 Django ORM 生成的 SQL 语句
  • 在实际开发中正确应用查询优化技巧

一、问题引入:N+1 查询问题

1.1 数据模型定义

# models.py
class Author(models.Model):name = models.CharField(max_length=100)country = models.CharField(max_length=50)class Book(models.Model):title = models.CharField(max_length=200)author = models.ForeignKey(Author, on_delete=models.CASCADE)publish_date = models.DateField()

1.2 存在性能问题的代码

# views.py (存在N+1查询问题)
books = Book.objects.all()
for book in books:print(f"书名:{book.title}, 作者:{book.author.name}")

1.3 对应的 SQL 查询

-- 第一次查询:获取所有书籍
SELECT "library_book"."id","library_book"."title", "library_book"."author_id","library_book"."publish_date"
FROM "library_book";-- 后续 N 次查询:为每本书单独查询作者
SELECT "library_author"."id", "library_author"."name", "library_author"."country"
FROM "library_author" WHERE "library_author"."id" = 1;SELECT "library_author"."id", "library_author"."name", "library_author"."country"
FROM "library_author" WHERE "library_author"."id" = 2;-- ... 依此类推,产生 N+1 次查询

问题分析:如果有 100 本书,将产生 101 次数据库查询,严重影响性能。


二、解决方案:select_related

2.1 select_related 的基本用法

# views.py (优化后的代码)
books = Book.objects.select_related('author').all()
for book in books:print(f"书名:{book.title}, 作者:{book.author.name}")

2.2 优化后的 SQL

SELECT "library_book"."id","library_book"."title","library_book"."author_id", "library_book"."publish_date",-- 通过 JOIN 一次性获取作者信息"library_author"."id","library_author"."name","library_author"."country"
FROM "library_book"
INNER JOIN "library_author" ON ("library_book"."author_id" = "library_author"."id");

优化效果:无论有多少本书,都只执行 1 次 数据库查询。


三、select_related 的深入使用

3.1 深度关联查询

扩展数据模型:

class Country(models.Model):name = models.CharField(max_length=50)code = models.CharField(max_length=3)class Author(models.Model):name = models.CharField(max_length=100)country = models.ForeignKey(Country, on_delete=models.CASCADE)class Book(models.Model):title = models.CharField(max_length=200)author = models.ForeignKey(Author, on_delete=models.CASCADE)publish_date = models.DateField()

深度关联查询:

# 一次性获取 Book -> Author -> Country 的所有数据
books = Book.objects.select_related('author__country').all()
for book in books:print(f"{book.title} - {book.author.name} - {book.author.country.name}")

对应的 SQL:

SELECT "library_book"."id","library_book"."title","library_book"."author_id","library_book"."publish_date",-- 作者表字段"library_author"."id","library_author"."name", "library_author"."country_id",-- 国家表字段(通过第二次 JOIN)"library_country"."id","library_country"."name","library_country"."code"
FROM "library_book"
INNER JOIN "library_author" ON ("library_book"."author_id" = "library_author"."id")
INNER JOIN "library_country" ON ("library_author"."country_id" = "library_country"."id");

四、实践技巧与注意事项

4.1 查看生成的 SQL 语句

方法1:使用 query 属性

books = Book.objects.select_related('author')
print(books.query)

方法2:配置 Django SQL 日志
settings.py 中添加:

LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'console': {'level': 'DEBUG','class': 'logging.StreamHandler',},},'loggers': {'django.db.backends': {'handlers': ['console'],'level': 'DEBUG',},},
}

4.2 使用原则

  1. 适用场景

    • 一对一关系(OneToOneField)
    • 多对一关系(ForeignKey)
    • 需要立即访问关联对象字段时
  2. 不适用场景

    • 多对多关系(ManyToManyField)
    • 反向的多对一关系
    • 对于这些情况,应该使用 prefetch_related
  3. 注意事项

    • 不要过度使用深度关联
    • 考虑查询返回的数据量
    • 只在确实需要访问关联对象时使用

五、总结对比

5.1 性能对比表

查询方式查询次数适用场景SQL 类型
普通查询N+1 次不确定是否需要关联对象简单查询 + 多次关联查询
select_related1 次确定需要访问关联对象的所有字段JOIN 查询

5.2 核心要点

  1. 解决问题:N+1 查询问题
  2. 实现原理:使用 SQL JOIN 语句一次性加载关联数据
  3. 使用语法Model.objects.select_related('foreign_key_field')
  4. 深度关联:使用双下划线 'field__related_field'
  5. 记忆口诀:“往前拿,用 select_related

5.3 最佳实践

# 好的实践:明确知道需要作者信息
books = Book.objects.select_related('author').filter(publish_date__year=2023)
for book in books:# 这里会频繁访问 author 的字段display_info = f"{book.title} by {book.author.name}"# 不好的实践:不确定是否需要关联对象
books = Book.objects.select_related('author').filter(publish_date__year=2023)
for book in books:# 如果这里根本不访问 book.author,就浪费了 JOIN 的性能print(book.title)
http://www.dtcms.com/a/540440.html

相关文章:

  • Django 与 FastAPI 架构对比:学习路径指南
  • 【Axure教程】能展开查看附件的嵌套表格
  • 装修网站线怎样做中国制造网外贸平台下载
  • GPT结构剖析:从“词袋”到“思想”的魔法之旅
  • u盘安装系统提示“windows无法安装到这个磁盘,选中的磁盘具有gpt分区表”解决方法
  • WebRTC 集成 FFmpeg HEVC 硬件解码(hevc_cuvid)avcodec_open2错误码-558323010
  • 阿里国际AI翻译模型Marco霸榜WMT,英中赛道超越GPT-4.1与Gem
  • 三星单片机开发网站店铺装修一平方大概多少钱
  • 麒麟系统拔掉鼠标键盘再插上,鼠标键盘没反应
  • 做内贸只要有什么网络推广网站wordpress更新需要ftp
  • FastReport VCL发布2026.1版本:全面支持RAD Studio 13,PDF输出功能显著增强
  • SpringBoot3整合JetCache缓存
  • 云原生周刊:在 Kubernetes 上运行机器学习
  • nacos多个实例,如果让多个实例同时更新缓存 实现方案
  • Redis连接超时排查与优化指南
  • 织梦小说网站模板下载地址做手机网站用什么软件
  • 网站怎么添加链接代码网站的倒计时怎么做
  • 1472. 设计浏览器历史记录
  • ETCD 集群备份与恢复
  • ETCD 常用命令
  • 低空经济网络安全风险
  • 【音视频】B站的流媒体协议
  • GVHMR——基于重力-视角坐标的人体运动恢复:从RGB视频中提取人的SMPL轨迹(包含人体姿态估计WHAM、手势估计HaMeR的详解)
  • 【ROS2】驱动开发-通过控制器访问硬件(Hardware Access through Controllers)
  • 智能网联汽车网络发展总体目标:构建“泛在接入、能力协同、安全可信“的立体化体系
  • 网站可以备案先提交类别后来改么网站如何被百度快速收录
  • 【软考架构】案例分析:状态图和活动图的定义以及区别
  • 制作营销网站公司有没有做网站的
  • HarmonyOS 性能优化与安全开发:打造高效且安全的智能应用
  • 从TSX到JS:深入解析npm run build背后的完整构建流程