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

Django-ORM-select_related

Django-ORM-select_related

  • 作用
  • 使用场景
  • 示例
    • 无 select_related 的查询
    • 有 select_related 的查询
  • 如何理解 "只发起一次查询,包含所有相关作者信息"
    • 1. select_related 的工作原理
    • 2. 具体示例解析
    • 3. 为什么只发起一次查询
  • 数据库中的books量巨大,使用`select_related`导致服务崩掉,如何解决
    • 程序层面优化
      • 1. 优化 select_related 的使用
      • 2. 限制查询字段
      • 3. 分页(Pagination)
        • 使用 Django 内置的分页器
        • 使用基于游标的分页(Cursor-based Pagination)
      • 4. 批量处理(Batch Processing)
      • 5. 使用 iterator
      • 6. 使用 prefetch_related 结合 select_related
      • 7. 数据库索引优化
      • 8. 缓存机制
      • 9. 异步处理
    • 数据库层面优化
      • 10. 数据库层面的优化

作用

select_related 主要用于优化一对一(OneToOneField)外键(ForeignKey) 关系中的查询。
它通过SQL的JOIN操作,在单个查询中获取相关对象的数据,从而减少数据库查询次数。

使用场景

• 当你需要访问外键或一对一关系的相关对象时。
• 适用于深度较浅的关系(通常一层或两层)。

示例

假设有以下模型:

from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=100)class Book(models.Model):title = models.CharField(max_length=100)author = models.ForeignKey(Author, on_delete=models.CASCADE)

无 select_related 的查询

books = Book.objects.all()
for book in books:print(book.author.name)  # 每次循环都会发起一次数据库查询

上述代码会对每个 book 对象的 author 执行一次额外的查询,导致“N+1查询问题”。

有 select_related 的查询

books = Book.objects.select_related('author').all()
for book in books:print(book.author.name)  # 只发起一次查询,包含所有相关作者信息

通过 select_related,Django 在单个查询中使用JOIN语句同时获取 Book 和对应的 Author 数据,避免了多次查询。

当然,理解 select_related 如何实现“只发起一次查询,包含所有相关作者信息”对于掌握Django的查询优化至关重要。让我们深入探讨这一过程,包括Django如何构建SQL查询、执行查询以及处理结果。


如何理解 “只发起一次查询,包含所有相关作者信息”

1. select_related 的工作原理

select_related 通过SQL JOIN 操作将主查询和相关模型的查询合并为一个单一的数据库查询。这意味着,当你调用 select_related 时,Django会在后台构造一个包含JOIN的SQL语句,一次性从数据库中获取所有需要的数据。

2. 具体示例解析

当你执行 Book.objects.select_related('author').all() 时,Django会生成一个包含JOIN的SQL查询。

SELECT book.id, book.title, book.author_id, author.id, author.name
FROM book
INNER JOIN author ON book.author_id = author.id;

这个查询通过 INNER JOINbook 表和 author 表连接起来,一次性获取所有书籍及其对应的作者信息。
Django将上述SQL语句发送到数据库执行。数据库处理JOIN操作并返回一个包含所有书籍和作者信息的结果集。

Django的ORM会将查询结果映射到相应的Python对象中。具体来说:

• 每个 Book 实例都会包含其相关联的 Author 实例。
• 这些 Author 实例已经被预先加载,不需要额外的数据库查询。

因此,当你迭代 books 并访问 book.author.name 时,Django已经拥有了所有必要的数据,直接从内存中获取 author.name,而不会发起新的数据库查询。

3. 为什么只发起一次查询

关键在于 select_related 使用了JOIN操作,将多个表的数据合并到一个结果集中。这意味着:

单一查询:只需要执行一次SQL查询,就可以获取所有相关的数据。
减少开销:避免了“N+1查询问题”,即避免了对每个 Book 对象都执行一次额外的查询来获取其 Author


数据库中的books量巨大,使用select_related导致服务崩掉,如何解决

程序层面优化

拿时间换空间:

  • 通过加一些条件只在必要的时候使用 select_related
  • 只查询必要字段
  • 分页
  • 分批
  • 迭代器
  • 缓存
  • 异步

1. 优化 select_related 的使用

如果某些关联数据不需要,可以避免使用 select_related,或者在必要时才使用。

# 只在需要时使用 select_related
books = Book.objects.all()
for book in books:if some_condition(book):author = book.author  # 触发单独的查询print(author.name)

或者分情况使用 select_related

books = Book.objects.filter(some_field=some_value).select_related('author')
for book in books:print(book.author.name)

2. 限制查询字段

只选择需要的字段,减少每次查询的数据量。

books = Book.objects.select_related('author').only('title', 'author__name')
for book in books:print(book.author.name)

或者使用 valuesvalues_list

books = Book.objects.select_related('author').values('title', 'author__name')
for book in books:print(book['author__name'])

3. 分页(Pagination)

将查询结果分批加载,每次只处理一部分数据,避免一次性加载所有记录。

使用 Django 内置的分页器
from django.core.paginator import Paginatorbooks = Book.objects.select_related('author').all()paginator = Paginator(books, 100)  # 每页100条记录page_number = 1
while True:page = paginator.get_page(page_number)if not page:breakfor book in page:print(book.author.name)page_number += 1
使用基于游标的分页(Cursor-based Pagination)

对于大数据量且需要高效分页的场景,基于游标的分页更为适用。

from django.db import connectionbooks = Book.objects.select_related('author').order_by('id')  # 确保有排序字段batch_size = 1000
offset = 0while True:batch = books[offset:offset + batch_size]if not batch:breakfor book in batch:print(book.author.name)offset += batch_size

注意:对于非常大的数据集,建议使用基于游标的分页库,如 django-elasticsearch-dsl 或其他支持高效分页的工具。

4. 批量处理(Batch Processing)

将数据分成较小的批次进行处理,避免一次性加载所有数据。

from django.db import transactionbatch_size = 1000
books = Book.objects.select_related('author').all()for i in range(0, books.count(), batch_size):batch = books[i:i + batch_size]with transaction.atomic():  # 根据需要使用事务for book in batch:print(book.author.name)

5. 使用 iterator

iterator 方法可以逐批从数据库中获取数据,减少内存消耗。

books = Book.objects.select_related('author').all().iterator()for book in books:print(book.author.name)

注意:使用 iterator 后,无法再次遍历查询集,且缓存机制会有所不同。

6. 使用 prefetch_related 结合 select_related

在某些复杂查询中,可以结合使用 select_relatedprefetch_related 来优化性能。

books = Book.objects.select_related('author').prefetch_related('other_related_field')
for book in books:print(book.author.name)

但对于大数据量,通常建议优先考虑分页或批量处理。

7. 数据库索引优化

确保在 Book 表的 author_id 字段上有索引,以加快 JOIN 操作的速度。

class Book(models.Model):title = models.CharField(max_length=100)author = models.ForeignKey(Author, on_delete=models.CASCADE, db_index=True)  # 确保有索引

8. 缓存机制

对于不经常变化的数据,可以使用缓存来减少数据库查询次数。

from django.core.cache import cachedef get_books():books = cache.get('all_books')if not books:books = list(Book.objects.select_related('author').all().iterator())cache.set('all_books', books, timeout=60*15)  # 缓存15分钟for book in books:print(book.author.name)

注意:缓存大数据量可能会占用大量内存,需谨慎使用。

9. 异步处理

将耗时的处理任务放到异步队列中执行,如 Celery,避免阻塞主线程。

# tasks.py
from celery import shared_task
from .models import Book@shared_task
def process_books():books = Book.objects.select_related('author').all().iterator()for book in books:print(book.author.name)# 在视图中调用
process_books.delay()

数据库层面优化

10. 数据库层面的优化

https://blog.csdn.net/2303_78378466/article/details/145123310

分表分库:将 books 表拆分成多个子表或数据库,减少单个查询的压力。
读写分离:将读操作和写操作分离到不同的数据库实例,提升查询性能。
使用更高效的数据库:如 PostgreSQL 在处理复杂查询时性能更优,可以考虑切换数据库。

Django-ORM-select_related

  • 作用
  • 使用场景
  • 示例
    • 无 select_related 的查询
    • 有 select_related 的查询
  • 如何理解 "只发起一次查询,包含所有相关作者信息"
    • 1. select_related 的工作原理
    • 2. 具体示例解析
    • 3. 为什么只发起一次查询
  • 数据库中的books量巨大,使用`select_related`导致服务崩掉,如何解决
    • 程序层面优化
      • 1. 优化 select_related 的使用
      • 2. 限制查询字段
      • 3. 分页(Pagination)
        • 使用 Django 内置的分页器
        • 使用基于游标的分页(Cursor-based Pagination)
      • 4. 批量处理(Batch Processing)
      • 5. 使用 iterator
      • 6. 使用 prefetch_related 结合 select_related
      • 7. 数据库索引优化
      • 8. 缓存机制
      • 9. 异步处理
    • 数据库层面优化
      • 10. 数据库层面的优化

相关文章:

Django-ORM-select_related

Django-ORM-select_related 作用使用场景示例无 select_related 的查询有 select_related 的查询 如何理解 "只发起一次查询,包含所有相关作者信息"1. select_related 的工作原理2. 具体示例解析3. 为什么只发起一次查询 数据库中的books量巨大&#xff0…...

蓝桥杯 k倍区间

题目描述 给定一个长度为 NN 的数列,A1,A2,⋯ANA1​,A2​,⋯AN​,如果其中一段连续的子序列 Ai,Ai1,⋯AjAi​,Ai​1,⋯Aj​ ( i≤ji≤j ) 之和是 KK 的倍数,我们就称这个区间 [i,j][i,j] 是 K 倍区间。 你能求出数列中总共有多少个 KK 倍区间…...

数据结构(蓝桥杯常考点)

数据结构 前言:这个是针对于蓝桥杯竞赛常考的数据结构内容,基础算法比如高精度这些会在下期给大家总结 数据结构 竞赛中,时间复杂度不能超过10的7次方(1秒)到10的8次方(2秒) 空间限制&#x…...

Tomcat+Servlet运行后出现404错误解决方案

TomcatServlet运行后出现404错误解决方案 一、错误效果复现 后续的解决方案,仅仅针对我遇到的情况。对不能涵盖大部分情况感到抱歉。 二、错误分析 先看看源代码? package com.example.secondclass.Servlet; import java.io.*; import jakarta.servl…...

论文摘要生成器:用TextRank算法实现文献关键信息提取

我们基于python代码,使用PyQt5创建图形用户界面(GUI),同时支持中英文两种语言的文本论文文献关键信息提取。 PyQt5:用于创建GUI应用程序。 jieba:中文分词库,用于中文文本的处理。 re&#xff…...

Flutter中网络图片加载显示Image.network的具体用法

Image.network的具体用法 Image.network 是 Flutter 中用于从网络加载图片的便捷方法。它基于 NetworkImage,可以快速加载并显示网络图片。以下是 Image.network 的具体用法和常见参数说明。 基本用法 最简单的用法是提供一个图片的 URL: dart 复制 …...

【HarmonyOS Next】鸿蒙应用故障处理思路详解

【HarmonyOS Next】鸿蒙应用崩溃处理思路详解 一、崩溃问题发现后定位 1. 崩溃现象: 常见的崩溃问题表现为,应用操作后白屏闪退,或者应用显示无响应卡死。 2.定位问题: 发现崩溃后,我们首先需要了解复现步骤&#x…...

狮子座大数据分析(python爬虫版)

十二星座爱情性格 - 星座屋 首先找到一个星座网站,作为基础内容,来获取信息 网页爬取与信息提取 我们首先利用爬虫技术(如 Python 中的 requests 与 BeautifulSoup 库)获取页面内容。该页面(xzw.com/astro/leo/&…...

QT系列教程(18) MVC结构之QItemSelectionModel模型介绍

视频教程 https://www.bilibili.com/video/BV1FP4y1z75U/?vd_source8be9e83424c2ed2c9b2a3ed1d01385e9 QItemSelectionModel Qt的MVC结构支持多个View共享同一个model,包括该model的选中状态等。我们可以通过设置QItemSelectionModel,来更改View的选…...

git设置本地仓库和远程仓库

设置本地仓库和远程仓库是使用Git进行版本控制的基本操作。以下是详细步骤: 创建本地仓库 初始化本地仓库: 打开命令行工具(如Terminal或Git Bash)。导航到你希望创建Git仓库的项目文件夹。运行以下命令来初始化一个新的Git仓库&…...

openharmony中HDF驱动框架源码梳理-驱动加载流程

要想大概了解一个公司,我们可能只需要知道它的运行逻辑即可,例如我们只需要知道它有财务有研发有运营等,财务报销、研发负责产品等即可,但是如果想深入具体的了解的话我们就要了解都有什么部门(对象)、各部门都包含哪些职责(对象方…...

golang 高性能的 MySQL 数据导出

需求导出方式对比方案1:快照导出(耗时:1.5s)方案2: 偏移分页(耗时:4s)方案 3:普通分页(耗时:4min40s) 需求 导出 MySQL 数据 分析: 一次性 select 大量数据带来的问题 性能问题: 数据库负载:大量数据查询会增加数据库的CPU、内存和I/O负担&#xff…...

31-判断子序列

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列&#x…...

leetcode日记(95)将有序数组转换为二叉搜索树

很简单,感觉自己越来越适应数据结构题目了…… /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : va…...

使用SSH密钥连接本地git 和 github

目录 配置本地SSH,添加到github首先查看本地是否有SSH密钥生成SSH密钥,和邮箱绑定将 SSH 密钥添加到 ssh-agent:显示本地公钥*把下面这一串生成的公钥存到github上* 验证SSH配置是否成功终端跳转到本地仓库把http协议改为SSH(如果…...

C语言基础之【内存管理】

C语言基础之【内存管理】 存储类型作用域普通局部变量静态局部变量普通全局变量静态全局变量全局函数和静态函数 内存布局内存分区存储类型与内存四区内存操作函数memset()memcpy()memmove()memcmp() 堆区内存分配和释放malloc()free() 内存分区代码分析返回栈区地址返回data区…...

C盘清理技巧分享:释放空间,提升电脑性能

目录 1. 引言 2. C盘空间不足的影响 3. C盘清理的必要性 4. C盘清理的具体技巧 4.1 删除临时文件 4.2 清理系统还原点 4.3 卸载不必要的程序 4.4 清理下载文件夹 4.5 移动大文件到其他盘 4.6 清理系统缓存 4.7 使用磁盘清理工具 4.8 清理Windows更新文件 4.9 禁用…...

每天一道算法题【蓝桥杯】【两两交换链表中的节点】

思路 本质问题可以分成若干个子问题 即把前两个链表交换,并与后面的链表相连 故实现函数功能调用自身递归即可 #define _CRT_SECURE_NO_WARNINGS 1 struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), nex…...

mIoU Class与mIoU Category的区别

mIoU(mean Intersection over Union)是语义分割任务中常用的评估指标,用于衡量模型预测的分割结果与真实标签之间的重叠程度。mIoU Class 和 mIoU Category 的区别主要体现在计算方式和应用场景上: 1. mIoU Class 定义&#xff…...

深入解析 C 语言中含数组和指针的构造体与共同体内存计算

在 C 语言中,构造体(struct)和共同体(union)允许我们将多种数据类型组合到一起。除了常见的基本数据类型之外,经常还会在它们中嵌入数组和指针。由于数组的内存是连续分配的,而指针的大小与平台…...

Ubuntu系统下交叉编译openssl

一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !

我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...