当前位置: 首页 > 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)允许我们将多种数据类型组合到一起。除了常见的基本数据类型之外,经常还会在它们中嵌入数组和指针。由于数组的内存是连续分配的,而指针的大小与平台…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

企业如何增强终端安全?

在数字化转型加速的今天&#xff0c;企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机&#xff0c;到工厂里的物联网设备、智能传感器&#xff0c;这些终端构成了企业与外部世界连接的 “神经末梢”。然而&#xff0c;随着远程办公的常态化和设备接入的爆炸式…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...