在本文中,您将了解 N 1 查询、如何使用 AppSignal 检测它们,以及如何修复它们以显着加快 Django 应用程序的速度。
我们将从理论方面开始,然后转向实际示例。实际示例将反映您在生产环境中可能遇到的场景。
让我们开始吧!
什么是 N 1 查询?
N 1 查询问题是与数据库交互的 Web 应用程序中普遍存在的性能问题。这些查询可能会导致严重的瓶颈,并且随着数据库的增长而加剧。
当您检索对象集合,然后访问集合中每个项目的相关对象时,就会出现问题。例如,获取书籍列表需要单个查询(1 个查询),但访问每本书的作者会触发对每个项目的额外查询(N 个查询)。
在数据库中创建或更新数据时也可能会出现 N 1 问题。例如,通过循环迭代来单独创建或更新对象,而不是使用bulk_create() 或bulk_update() 等方法,可能会导致过多的查询。
N 1 查询效率极低,因为执行大量小查询比将操作合并为更少、更大的查询要慢得多,而且更耗费资源。
Django 的默认 QuerySet 行为可能会无意中导致 N 1 问题,特别是如果您不知道 QuerySet 是如何工作的。 Django 中的查询集是惰性的,这意味着在对查询集求值之前不会执行任何数据库查询。
先决条件
确保您拥有:
- Python 3.9 和 Git 安装在本地计算机上
- 支持 AppSignal 的操作系统
- AppSignal 帐户
注意:此项目的源代码可以在 appsignal-django-n-plus-one GitHub 存储库中找到。
项目设置
我们将使用图书管理网络应用程序。该 Web 应用程序旨在演示 N 1 查询问题以及如何解决它。
首先克隆 GitHub 存储库的基础分支:
$ git clone git@github.com:duplxey/appsignal-django-n-plus-one.git \ --single-branch --branch base && cd appsignal-django-n-plus-one
接下来,创建并激活虚拟环境:
$ python3 -m venv venv && source venv/bin/activate
安装要求:
(venv)$ pip install -r requirements.txt
迁移并填充数据库:
(venv)$ python manage.py migrate (venv)$ python manage.py populate_db
最后,启动开发服务器:
(venv)$ python manage.py runserver
打开您最喜欢的网络浏览器并导航到 http://localhost:8000/books。 Web 应用程序应从数据库返回包含 500 本书的 JSON 列表。
Django 管理站点可通过 http://localhost:8000/admin 访问。管理员凭据是:
user: username pass: password
为 Django 安装 AppSignal
要在 Django 项目上安装 AppSignal,请按照官方文档操作:
- AppSignal Python 安装
- AppSignal Django 工具
- AppSignal SQLite 工具
通过重新启动开发服务器确保一切正常:
$ git clone git@github.com:duplxey/appsignal-django-n-plus-one.git \ --single-branch --branch base && cd appsignal-django-n-plus-one
您的应用程序应自动向 AppSignal 发送演示错误。从此时起,您的所有错误都将发送到 AppSignal。此外,AppSignal 将监控您应用的性能并检测任何问题。
网络应用程序逻辑
修复 N 1 查询的先决条件是了解应用程序的数据库架构。密切关注模型的关系:它们可以帮助您查明潜在的 N 1 问题。
型号
Web 应用程序有两个模型 - 作者和书籍 - 它们共享一对多 (1:M) 关系。这意味着每本书都与一个作者相关联,而一个作者可以链接到多本书。
两个模型都有一个 to_dict() 方法,用于将模型实例序列化为 JSON。最重要的是,Book 模型使用深度序列化(序列化书籍以及书籍的作者)。
模型在 books/models.py 中定义:
$ python3 -m venv venv && source venv/bin/activate
然后它们在 books/admin.py 中注册 Django 管理站点,如下所示:
(venv)$ pip install -r requirements.txt
请注意,AuthorAdmin 使用 BookInline 在作者的管理页面中显示作者的书籍。
意见
网络应用程序提供以下端点:
- /books/ 返回书籍列表
-
/books/
/ 返回特定书籍 - /books/by-authors/ 返回按作者分组的书籍列表
- /books/authors/ 返回作者列表
-
/books/authors/
/ 返回特定作者
如果您正在运行开发网络服务器,则可以单击上面的链接。
它们在 books/views.py 中定义如下:
(venv)$ python manage.py migrate (venv)$ python manage.py populate_db
太棒了,您现在知道网络应用程序是如何工作的!
在下一节中,我们将对我们的应用程序进行基准测试,以使用 AppSignal 检测 N 1 个查询,然后修改代码以消除它们。
使用 AppSignal 检测 Django 应用中的 N 1 查询
使用 AppSignal 检测性能问题很容易。您所要做的就是像平常一样使用/测试应用程序(例如,通过访问所有端点并验证响应来执行最终用户测试)。
当某个端点被命中时,AppSignal 将为其创建一份性能报告,并将所有相关访问分组在一起。每次访问都将作为样本记录在端点的报告中。
检测视图中的 N 1 个查询
首先,访问您应用程序的所有端点以生成性能报告:
- /书籍/
- /books/
/ - /书籍/作者/
- /书籍/作者/
- /books/authors/
/
接下来,让我们使用 AppSignal 仪表板来分析慢速端点。
示例 1:一对一关系 (select_lated())
导航到您的 AppSignal 应用程序并选择 性能 >侧边栏上的问题列表。然后单击平均值 按平均响应时间降序对问题进行排序。
点击最慢的端点(books/)查看其详细信息。
查看最新示例,我们可以看到该端点在 1090 毫秒内返回响应。组细分显示 SQLite 需要 651 毫秒,而 Django 需要 439 毫秒。
这表明存在问题,因为像这样简单的端点不应该花费那么长的时间。
要获取有关所发生事件的更多详细信息,请选择侧边栏中的示例,然后选择最新示例。
向下滚动到事件时间线以查看执行了哪些 SQL 查询。
将鼠标悬停在 query.sql 文本上会显示实际的 SQL 查询。
执行了超过 1000 个查询:
$ git clone git@github.com:duplxey/appsignal-django-n-plus-one.git \ --single-branch --branch base && cd appsignal-django-n-plus-one
这些是 N 1 个查询的明显标志。第一个查询获取一本书 (1),随后的每个查询获取该书的作者详细信息 (N)。
要修复它,请导航到 books/views.py 并修改 book_list_view(),如下所示:
$ python3 -m venv venv && source venv/bin/activate
通过利用 Django 的 select_lated() 方法,我们在初始查询中选择附加的相关对象数据(即作者)。 ORM 现在将利用 SQL 连接,最终查询将如下所示:
(venv)$ pip install -r requirements.txt
等待开发服务器重新启动并重新测试受影响的端点。
再次进行基准测试后,响应时间从 1090 减少到 45,查询数量从 1024 减少到 2。分别提高了 24 倍和 512 倍。
示例 2:多对一关系 (prefetch_lated())
接下来,让我们看看第二慢的端点(books/by-authors/)。
像我们在上一步中所做的那样使用仪表板来检查端点的 SQL 查询。您会注意到此端点有类似但不太严重的 N 1 模式。
这个端点的性能不太严重,因为 Django 足够聪明,可以缓存频繁执行的 SQL 查询,即重复获取一本书的作者。查看官方文档以了解有关 Django 缓存的更多信息。
让我们利用 books/views.py 中的 prefetch_lated() 来加速端点:
$ git clone git@github.com:duplxey/appsignal-django-n-plus-one.git \ --single-branch --branch base && cd appsignal-django-n-plus-one
在上一节中,我们使用 select_lated() 方法来处理一对一关系(每本书都有一个作者)。然而,在本例中,我们正在处理一对多关系(一个作者可以拥有多本书),因此我们必须使用 prefetch_lated()。
这两种方法的区别在于 select_lated() 工作在 SQL 级别,而 prefetch_lated() 则在 Python 级别进行优化。后一种方法也可以用于多对多关系。
有关更多信息,请查看 Django 关于 prefetch_lated() 的官方文档。
基准测试后,响应时间从 90 毫秒减少到 44 毫秒,查询数量从 32 减少到 4。
在 Django Admin 中检测 N 1 个查询
在 Django 管理站点中发现 N 1 个查询的工作原理类似。
首先,登录您的管理站点并生成绩效报告(例如,创建一些作者或书籍,更新和删除它们)。
接下来,导航到您的 AppSignal 应用仪表板,这次由管理员过滤问题:
就我而言,两个最慢的端点是:
- /管理/登录
- /admin/books/author/
我们无法对 /admin/login 做太多事情,因为它完全由 Django 处理,所以让我们关注第二个最慢的端点。检查它会发现 N 1 查询问题。每本书都会单独获取作者。
要解决此问题,请重写 BookInline 中的 get_queryset() 以在初始查询中获取作者详细信息:
$ python3 -m venv venv && source venv/bin/activate
再次进行基准测试并验证查询数量是否有所减少。
总结
在这篇文章中,我们讨论了使用 AppSignal 检测和修复 Django 中的 N 1 个查询。
利用您在这里学到的知识可以帮助您显着加快 Django Web 应用程序的速度。
要记住的两个最重要的方法是 select_lated() 和 prefetch_lated()。第一个用于一对一关系,第二个用于一对多和多对多关系。
编码愉快!
P.S.如果您想在 Python 文章发布后立即阅读,请订阅我们的 Python Wizardry 时事通讯,不错过任何一篇文章!
以上是使用 AppSignal 在 Django 中查找并修复 N ueries的详细内容。更多信息请关注PHP中文网其他相关文章!

本文解释了如何使用美丽的汤库来解析html。 它详细介绍了常见方法,例如find(),find_all(),select()和get_text(),以用于数据提取,处理不同的HTML结构和错误以及替代方案(SEL)

Python的statistics模块提供强大的数据统计分析功能,帮助我们快速理解数据整体特征,例如生物统计学和商业分析等领域。无需逐个查看数据点,只需查看均值或方差等统计量,即可发现原始数据中可能被忽略的趋势和特征,并更轻松、有效地比较大型数据集。 本教程将介绍如何计算平均值和衡量数据集的离散程度。除非另有说明,本模块中的所有函数都支持使用mean()函数计算平均值,而非简单的求和平均。 也可使用浮点数。 import random import statistics from fracti

Python 对象的序列化和反序列化是任何非平凡程序的关键方面。如果您将某些内容保存到 Python 文件中,如果您读取配置文件,或者如果您响应 HTTP 请求,您都会进行对象序列化和反序列化。 从某种意义上说,序列化和反序列化是世界上最无聊的事情。谁会在乎所有这些格式和协议?您想持久化或流式传输一些 Python 对象,并在以后完整地取回它们。 这是一种在概念层面上看待世界的好方法。但是,在实际层面上,您选择的序列化方案、格式或协议可能会决定程序运行的速度、安全性、维护状态的自由度以及与其他系

本文比较了Tensorflow和Pytorch的深度学习。 它详细介绍了所涉及的步骤:数据准备,模型构建,培训,评估和部署。 框架之间的关键差异,特别是关于计算刻度的

本文讨论了诸如Numpy,Pandas,Matplotlib,Scikit-Learn,Tensorflow,Tensorflow,Django,Blask和请求等流行的Python库,并详细介绍了它们在科学计算,数据分析,可视化,机器学习,网络开发和H中的用途

本文指导Python开发人员构建命令行界面(CLIS)。 它使用Typer,Click和ArgParse等库详细介绍,强调输入/输出处理,并促进用户友好的设计模式,以提高CLI可用性。

该教程建立在先前对美丽汤的介绍基础上,重点是简单的树导航之外的DOM操纵。 我们将探索有效的搜索方法和技术,以修改HTML结构。 一种常见的DOM搜索方法是EX

文章讨论了虚拟环境在Python中的作用,重点是管理项目依赖性并避免冲突。它详细介绍了他们在改善项目管理和减少依赖问题方面的创建,激活和利益。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

WebStorm Mac版
好用的JavaScript开发工具

Atom编辑器mac版下载
最流行的的开源编辑器

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境