Django-ORM-prefetch_related

Django-ORM-prefetch_related

  • 模型定义
    • N+1 查询问题示例
  • 使用 prefetch_related 优化查询
  • 处理更复杂的查询
    • 示例:预取特定条件的书籍
    • 示例:预取多个关联字段
  • 性能比较
  • 注意事项
  • 总结

通过 AuthorBooks 两个模型来理解 Django 的 prefetch_related 方法。
探讨如何使用 prefetch_related 来优化查询,避免 N+1 查询问题,
并展示其在处理多对多关系和复杂查询中的强大功能。

模型定义

首先,假设我们有两个模型:AuthorBook。一个作者可以写多本书,一本书也可以有多个作者(多对多关系)。

from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=100)def __str__(self):return self.nameclass Book(models.Model):title = models.CharField(max_length=100)authors = models.ManyToManyField(Author, related_name='books')def __str__(self):return self.title

N+1 查询问题示例

假设我们想要获取所有作者以及他们所写的书籍。
如果不使用 prefetch_related,可能会遇到 N+1 查询问题。

# 获取所有作者
authors = Author.objects.all()for author in authors:print(f"Author: {author.name}")for book in author.books.all():  # 每个作者都会触发一次数据库查询print(f"  Book: {book.title}")

问题分析:
• 第一次查询获取所有作者。
• 对于每个作者,执行一次查询来获取其书籍。
• 如果有 10 个作者,总共会执行 1 + 10 = 11 次查询。

使用 prefetch_related 优化查询

prefetch_related 可以显著减少查询次数。
它会在后台执行额外的查询,并将结果缓存起来,
以便在访问关联对象时不需要额外的数据库查询。

# 使用 prefetch_related 预取每个作者的书籍
authors = Author.objects.prefetch_related('books')for author in authors:print(f"Author: {author.name}")for book in author.books.all():  # 现在只执行两次查询print(f"  Book: {book.title}")

优化效果:
• 第一次查询获取所有作者。
• 第二次查询获取所有相关的书籍。
• Django 在 Python 层面将这些书籍分配给相应的作者。
• 总共只执行了 2 次查询,无论有多少个作者。

处理更复杂的查询

有时候,我们可能需要预取多个关联字段,或者对预取的数据进行过滤。
这时,可以使用 Prefetch 对象来实现更细粒度的控制。

示例:预取特定条件的书籍

假设我们只想预取每位作者最近出版的 5 本书:

from django.db.models import Prefetch# 定义一个 Prefetch 对象,过滤并限制预取的书籍数量
recent_books = Prefetch('books',queryset=Book.objects.order_by('-id')[:5], # 假设 id 越大,出版时间越近to_attr='recent_books'                     # 将预取的书籍存储在 author.recent_books 中
)authors = Author.objects.prefetch_related(recent_books)for author in authors:print(f"Author: {author.name}")for book in author.recent_books:  # 访问预取的书籍print(f"  Recent Book: {book.title}")

解释:
• 使用 Prefetch 对象,我们可以自定义预取的查询集。
to_attr 参数指定了预取的数据存储在模型实例的哪个属性中。
• 这样可以避免加载所有关联对象,只加载我们需要的部分。

示例:预取多个关联字段

如果 Author 模型还有其他关联字段,比如 editor,我们可以同时预取多个关联:

authors = Author.objects.prefetch_related('books','editor'  # 假设有一个 ForeignKey 字段 'editor'
)for author in authors:print(f"Author: {author.name}")for book in author.books.all():print(f"  Book: {book.title}")if author.editor:print(f"  Editor: {author.editor.name}")

性能比较

为了更直观地理解 prefetch_related 的性能优势,我们来看一个简单的性能对比:

import time# 不使用 prefetch_related
start_time = time.time()
authors = Author.objects.all()
for author in authors:for book in author.books.all():pass  # 模拟操作
end_time = time.time()
print(f"无 prefetch_related 查询次数: {end_time - start_time} 秒")# 使用 prefetch_related
start_time = time.time()
authors = Author.objects.prefetch_related('books')
for author in authors:for book in author.books.all():pass  # 模拟操作
end_time = time.time()
print(f"使用 prefetch_related 查询次数: {end_time - start_time} 秒")

预期结果:
• 不使用 prefetch_related 的情况下,查询时间会随着作者数量的增加而线性增长。
• 使用 prefetch_related 后,查询时间基本保持不变,因为关联数据的查询次数大大减少。

注意事项

  1. 适用场景prefetch_related 主要用于处理“多对多”和“一对多”关系。对于“一对一”或“外键”关系,通常使用 select_related 更为高效。

  2. 内存消耗:由于 prefetch_related 会将所有预取的数据加载到内存中,如果关联数据量非常大,可能会导致内存占用过高。因此,在处理大数据集时需要谨慎使用。

  3. 自定义查询:通过 Prefetch 对象,可以自定义预取的查询集,如过滤、排序或限制数量,从而进一步优化性能。

  4. 链式调用prefetch_related 可以与其他查询优化方法(如 filterexclude 等)结合使用,以满足复杂的查询需求。

总结

prefetch_related 是 Django ORM 提供的一个强大的查询优化工具,特别适用于处理多对多和一对多关系中的 N+1 查询问题。通过预先加载关联对象,prefetch_related 能够显著减少数据库查询次数,提高应用的性能。在使用时,需要根据具体的业务场景选择合适的预取策略,并注意内存消耗等问题,以达到最佳的优化效果。

希望通过以上的解释和示例,你对 django-prefetch_related 有了更深入的理解!

Django-ORM-prefetch_related

  • 模型定义
    • N+1 查询问题示例
  • 使用 prefetch_related 优化查询
  • 处理更复杂的查询
    • 示例:预取特定条件的书籍
    • 示例:预取多个关联字段
  • 性能比较
  • 注意事项
  • 总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/73043.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot3整合Knife4j(4.5.0)

整体概述 Spring Boot 是用于简化 Spring 应用开发的框架,通过自动配置和约定大于配置原则,能让开发者快速搭建和运行 Spring 应用。Knife4j 是基于 Swagger 增强的 API 文档生成工具,可方便展示和调试 API 接口,生成美观易用的 …

Java 大视界 -- 区块链赋能 Java 大数据:数据可信与价值流转(84)

💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…

K8S学习之基础二十四:k8s的持久化存储之pv和pvc

K8S的存储之pv和pvc 在 Kubernetes (k8s) 中,持久化存储是通过 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 来实现的。PVC 是用户对存储资源的请求,而 PV 是集群中的实际存储资源。PVC 和 PV 的关系类似于 Pod 和 Node 的关系。 Persisten…

【Hive】Hive安装

Hive 第一章 Hive的基础知识 第二章 Hive安装 第三章 DDL(Data Definition Language)数据定义 第四章 DML(Data Manipulation Language)数据操作 第五章 Hive查询 第六章 Hive的基础知识 第七章 Hive函数 第八章 分区表和分桶表 …

关于C/C++语言的初学者在哪刷题,怎么刷题

引言: 这篇博客主要是针对初学者关于怎么在网上刷题,以及在哪里刷题。 1.介绍平台(在哪刷题): 1.牛客牛客网https://www.nowcoder.com/ :有许多面试题,也有许多供学习者练习的题 2.洛谷洛谷 …

k8s面试题总结(十四)

什么是Helm? Helm是一个k8s的包管理工具,它简化了应用程序在k8s集群中的部署,管理和维护。类似于rpm包和yum之间的关系。 K8s传统方式:类似于rpm安装包的方式,逐步进行安装,遇到依赖还得解决依赖问题 he…

物理服务器的作用都有哪些?

物理服务器是一种高性能的专用服务器,一般会被运用在大型组织和云计算环境当中,可以为企业和用户提供数据存储和计算资源,帮助企业提高整体的工作效率和快速实现业务目标。 物理服务器有着较高的安全性,企业可以将重要的数据信息备…

01 音视频知识学习(视频)

图像基础概念 ◼像素:像素是一个图片的基本单位,pix是英语单词picture的简写,加上英 语单词“元素element”,就得到了“pixel”,简称px,所以“像素”有“图像元素” 之意。 ◼ 分辨率:是指图像…

有关MyBatis的动态SQL

有关MyBatis动态SQL MyBatis动态SQL是一种根据不同条件灵活拼接SQL语句的技术,基于OGNL表达式实现。动态 SQL 大大减少了编写代码的工作量,更体现了 MyBatis 的灵活性、高度可配置性和可维护性。 1.什么是动态SQL? 动态sql可以在一些需要灵活拼接sql…

react使用拖拽,缩放组件,采用react-rnd解决 -完整版

屏幕录制2025-03-10 10.16.06 以下代码仅提供左侧可视化区域 右侧数据根据你们的存储数据来 大家直接看Rnd标签设置的属性即可!!!!! /*** 用户拖拽水印的最终位置信息*/ export interface ProductWatermarkValue {wat…

Spring Cloud之远程调用OpenFeign参数传递

目录 OpenFeign参数传递 传递单个参数 传递多个参数 传递对象 传递JSON OpenFeign参数传递 传递单个参数 服务提供方product-service RequestMapping("/product") RestController public class ProductController {Autowiredprivate ProductService productSe…

每日一练之移除链表元素

题目: 画图解析: 方法:双指针 解答代码(注:解答代码带解析): //题目给的结构体 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* }…

从零开始的python学习(五)P75+P76+P77+P78+P79+P80

本文章记录观看B站python教程学习笔记和实践感悟,视频链接:【花了2万多买的Python教程全套,现在分享给大家,入门到精通(Python全栈开发教程)】 https://www.bilibili.com/video/BV1wD4y1o7AS/?p6&share_sourcecopy_web&v…

基于SpringBoot实现旅游酒店平台功能八

一、前言介绍: 1.1 项目摘要 随着社会的快速发展和人民生活水平的不断提高,旅游已经成为人们休闲娱乐的重要方式之一。人们越来越注重生活的品质和精神文化的追求,旅游需求呈现出爆发式增长。这种增长不仅体现在旅游人数的增加上&#xff0…

FastAPI 分页模块实现详解

1. 简介 本文详细介绍了一个基于 FastAPI 框架的通用分页处理模块的实现。该模块提供了标准的分页参数处理、数据切片和响应格式化功能,可以轻松地集成到任何 FastAPI 项目中。 2. 代码实现 2.1 导入必要的模块 首先,我们需要导入所需的模块&#xf…

Java 学习记录:基础到进阶之路(一)

今天,让我们深入到 Java 项目构建、基础语法及核心编程概念的领域,一探究竟。 软件安装及环境配置请查看之前更新的博客有着详细的介绍: IDEA软件安装&环境配置&中文插件-CSDN博客 目录 1.Java 项目构建基础 1.项目中的 SRC 目录…

Yashan DB 对象管理

一、什么是数据库对象 数据库对象是数据库里面用来存储和指向数据的各种概念和结构的总称。数据库支持的对象包括: • 表:表是一个逻辑概念,是数据库组织管理数据的基本单位。 • 索引:索引是建立在表上的逻辑对象,索…

deepseek 3FS编译

3FS在ubuntu22.04下的编译(记录下编译过程,方便后续使用) 环境信息 OS ubuntu 22.04内核版本 6.8.0-52-genericlibfuse 3.16.1rust 1.75.0FoundationDB 7.1.66meson 1.0.0ninja 1.10.1 libfuse编译 以下建议均在root下执行 pip3 install…

python-uiautomator2 安装教程

目录 一、简介 二、支持平台及语言 三、工作原理 四、安装 一、简介 uiautomator2是一个python库,用于Android的UI自动化测试,其底层基于Google uiautomator,Google提供的uiautomator库可以获取屏幕上任意一个APP的任意一个控件属性&…

无头浏览器与请求签名技术-Cloudflare防护

在实际数据采集实践中,许多目标网站(例如 Amazon)都会采用 Cloudflare 等防护措施,防止机器人和非正常流量。本文将分享一个故障场景下的排查与改进方案,讲述如何利用无头浏览器、请求签名技术以及爬虫代理 IP来实现数…