Django一分钟:使用prefetch_related避免陷入大量的查询中导致严重的性能问题

server/2024/10/21 5:50:31/

本文将通过简单的示例介绍为什么要使用prefetch_related

准备工作

创建模型

from django.db import modelsclass Product(models.Model):product_name = models.CharField(max_length=255)class Component(models.Model):product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='components')code = models.CharField(max_length=255)class Meta:ordering = ['product']

创建数据

>>> from api.models import Product
>>> p1 = Product.objects.create(product_name="产品1")
>>> p2 = Product.objects.create(product_name="产品2")
>>> from api.models import Component
>>> pc1 = Component.objects.create(product=p1, code="LS")
>>> pc2 = Component.objects.create(product=p1, code="LM")
>>> pc3 = Component.objects.create(product=p2, code="XYB")
>>> pc4 = Component.objects.create(product=p2, code="LXC")

settings.py文件中添加配置输出运行时执行的sql

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

不使用prefetch_related

from api.models import Product
ps = Product.objects.all()
# SELECT "api_product"."id", "api_product"."product_name" FROM "api_product"; args=(); alias=defaultfor p in ps:print(p.components.all())# SELECT "api_component"."id", "api_component"."product_id", "api_component"."code" FROM "api_component" WHERE "api_component"."product_id" = 1 ORDER BY "api_component"."product_id" ASC LIMIT 21; args=(1,);# SELECT "api_component"."id", "api_component"."product_id", "api_component"."code" FROM "api_component" WHERE "api_component"."product_id" = 2 ORDER BY "api_component"."product_id" ASC LIMIT 21; args=(2,);

不使用prefetch_related我们获取所有"产品"执行了一次sql查询,然而当我们遍历想要获取所有产品的组件时,对每个产品都执行了一次sql查询。

我们的示例中只产品的数量只有两个,当产品的数量非常多,成百上千时,对每个产品你都要到数据库执行一次查询,这将导致严重的性能问题,也就是所谓的n+1问题。

使用prefetch_related

from api.models import Product
ps = Product.objects.prefetch_related("components")
# SELECT "api_product"."id", "api_product"."product_name" FROM "api_product"; args=(); alias=default# SELECT "api_component"."id", "api_component"."product_id", "api_component"."code" FROM "api_component" WHERE "api_component"."product_id" IN (1, 2) ORDER BY "api_component"."product_id" ASC; args=(1, 2); alias=default
for p in ps:print(p.components.all())

可以清晰的看到总共执行了两次sql查询,在获取全部"产品"的时候通过一次额外的查询将所有产品的组件信息缓存起来,当我们需要的时候是从缓存中获取,不会执行任何的数据库查询

select_related

select_related只能用于一对一关系和外键关系,它是利用Join只进行一次SQL查询,但是它的局限也很明显,不能用于多对多,多对一等

from api.models import Component
c = Component.objects.select_related("product").get(pk=1)# SELECT "api_component"."id", "api_component"."product_id", "api_component"."code", "api_product"."id", "api_product"."product_name" FROM "api_component" INNER JOIN "api_product" ON ("api_component"."product_id" = "api_product"."id") WHERE "api_component"."id" = 1 LIMIT 21; args=(1,); alias=default

http://www.ppmy.cn/server/127370.html

相关文章

誉天Linux云计算课程学什么?为什么保障就业?

一个IT工程师相当于干了哪些职业? 其中置顶回答生动而形象地描绘道: 一个IT工程师宛如一个超级多面手,相当于——加班狂程序员测试工程师实施工程师网络工程师电工装卸工搬运工超人。 此中酸甜苦辣咸,相信很多小伙伴们都深有体会。除了典…

图片编辑添加文字,四款快速上手的软件分享

在这个视觉为王的时代,一张吸睛的图片往往能瞬间抓住读者的眼球。而想要在图片上优雅地添加文字,不仅能为作品增添灵魂,还能让你的社交媒体动态、博客文章或是产品展示更加生动有趣。今天,就为大家揭秘四款简单易上手、功能强大的…

角色动画——RootMotion全解

1. Unity(2022)的应用 由Animtor组件控制 在Animation Clip下可进行详细设置 ​ 官方文档的介绍(Animation选项卡 - Unity 手册) 上述动画类型在Rag选项卡中设置: Rig 选项卡上的设置定义了 Unity 如何将变形体映射到导入模型中的网格,以便能够将其动画化。 对于人…

Centos怎么执行脚本

方法一:切换到shell脚本所在的目录(此时,称为工作目录)执行shell脚本 cd /data/shell ./hello.sh 方法二:以绝对路径的方式去执行bash shell脚本 /data/shell/hello.sh 方法三:直接使用bash 或sh 来执行…

睡眠对于生活的重要性

在快节奏的现代生活中,健康养生不再是遥不可及的概念,而是融入日常每一刻的必需。其中,睡眠作为生命不可或缺的环节,其重要性往往被忽视,实则它是身体修复、能量积蓄的黄金时段。今天,让我们深入探讨“健康…

Web 服务器与动态脚本语言通信的接口协议有哪些

Web 服务器与动态脚本语言通信的接口协议主要有以下几种: 一、FastCGI(Fast Common Gateway Interface) 特点:使用持久进程处理请求,减少了进程启动和关闭的开销,提高了性能和可扩展性。多个请求可由同一个…

RLHF 的启示:微调 LSTM 能更好预测股票?

作者:老余捞鱼 原创不易,转载请标明出处及原作者。 写在前面的话: 在财务预测领域,准确预测股票价格是一项具有挑战性但至关重要的任务。传统方法通常难以应对股票市场固有的波动性和复杂性。这篇文章介绍了一种创新方法,该方法将长短期记忆 (LSTM) 网络与基于评…

忘记 MySQL 密码怎么办:破解 root 账户密码

忘记 MySQL 密码怎么办:破解 root 账户密码 目录 忘记 MySQL 密码怎么办:破解 root 账户密码1、修改 MySQL 配置文件2、不使用密码登录 MySQL3、重置 root 用户密码4、修改 MySQL 配置文件并重启 MySQL 服务5、使用新密码登录 MySQL 如果忘记密码导致无法…