如何在PHP中检测n+1查询问题及场景示例
php  /  管理员 发布于 6个月前   211
什么是 n+1 查询问题?
n+1 查询问题是软件开发中常见的性能问题。N+1 查询会导致许多不必要的数据库调用。
这会导致应用程序以蜗牛般的速度运行,尤其是当数据增长时。
因此,您必须了解并解决 N+1 查询问题,以确保您的应用程序高效、反应灵敏并具有可扩展性。
当应用程序进行一次数据库查询以检索一个对象,然后对检索到的每个对象进行其他查询
以获取相关对象时,就会出现 N+1 查询。
这样,N 个对象总共要执行 N+1 次数据库查询,这会大大降低应用程序的效率和性能,
尤其是在处理大型数据集时。
本文将探讨如何使用应用程序性能监控 (APM) 工具快速检测和解决 N+1 查询。
https://scoutapm.com/?utm_source=laravelnews&utm_medium=affiliate&utm_campaign=03_24&utm_content=n1_queries_in_php
n+1 查询示例:
让我们考虑一个需要显示作者及其书籍列表的书店应用程序。
应用程序可能首先查询数据库以检索所有作者(1 次查询)。
然后,针对检索到的每位作者,再进行一次查询,获取他们各自的书籍。
如果有 100 位作者,则总共需要 1 次查询(初始查询)+ 100 次查询(每位作者一次)= 101 次查询。
这样做效率很低,会严重降低应用程序的性能。
为了避免 N+1 查询问题,开发人员通常使用急切加载(在初始数据库查询中加载相关数据)或
https://sequelize.org/docs/v6/advanced-association-concepts/eager-loading/
批量获取(批量检索多个对象的相关数据)等技术。
https://stackoverflow.com/questions/8241822/php-mysql-running-query-in-batches
http://www.seancolombo.com/2009/07/05/quick-tip-do-huge-mysql-queries-in-batches-when-using-php/
如何检测 n+1 查询?
如果你有一个非同小可的应用程序,你很可能会有 n+1 查询。
如果你的应用程序是使用 Laravel 或 Symfony 等网络框架构建的,并且使用了 ORM,
那么肯定会有很多 n+1 查询。
这是因为许多现代网络框架的 ORM 层默认会懒加载记录。
在开发和测试环境中,N+1 查询问题很可能不会被注意到。
但是,当部署到生产环境时,这些问题可能会突然破坏应用程序的性能,
因为生产环境中数据库的行数要高得多。
应用程序存在 n+1 查询的主要标志是正在执行的数据库查询次数异常多。
这些查询通常是顺序进行且不重叠的。
这一切都很好,但你可能会问:
"好吧,但我怎么知道执行了多少次查询,以及这些查询是否'连续且不重叠'?
问得好!这就是应用程序性能监控 (APM) 工具的用武之地。
使用 APM 工具查找 n+1 查询:
应用程序性能监控工具,顾名思义,就是您可以用来监控和诊断应用程序问题的应用程序。
此类工具可以帮助您监控各种性能指标,包括数据库查询。
有许多不同的 APM 工具可供选择。
在本例中,我将使用 Scout APM。
https://scoutapm.com/?utm_source=laravelnews&utm_medium=affiliate&utm_campaign=03_24&utm_content=n1_queries_in_phpoutapm.com/
Scout APM 让查找 n+1 查询变得非常简单,因为它有一个专门的 n+1 insights 标签。
n+1 insights 标签会显示应用程序中所有端点的列表(红色高亮显示),对于每个端点,
你都可以看到运行了多少次查询以及查询花费了多长时间。点击单个端点将显示更深入的信息。
在端点详细信息页面上,你可以看到一个非常有用的时间轴视图,
例如,在部署更新后,你可以看到 n+1 出现的时间。
上面的截图描述的是浓缩视图,它能让你更直观地了解 n+1 查询的情况。
点击这里的 SQL 按钮(蓝色高亮显示),Scout 会向你显示值得指责的 SQL 查询。
回溯
在端点详细信息页面,你可以单击回溯按钮,找到 n+1 查询的确切代码行。
从上图中可以看到,Scout 追溯到了有问题的代码,准确找到了导致问题的行。
显示代码片段是因为我使用了 Scout 的 GitHub 集成。
https://scoutapm.com/docs/integrations
不过,即使你没有 GitHub 集成,Scout 仍会报告出问题代码文件和行号。
既然我们知道了如何使用 APM 追查 n+1 查询,那么接下来我们就来解决它们。
解决 n+1 查询
为了说明如何在使用 ORM(如 Laravel 的 Eloquent 或 Doctrine)的 PHP 应用程序中
解决 N+1 查询问题,我们将重温前面提到的基于书店应用场景的示例。
情景:
数据库中有两个表:作者和书籍。每个作者可以拥有多本书。
让我们先看看导致 N+1 查询问题的代码,然后再看看如何解决这个问题。
存在 N+1 查询问题的代码:
// Retrieve all authors
$authors = Author::all();
foreach($authors as $author) {
// For each author, retrieve their books$books = $author->books()->get(); // This causes an additional query for each author
// Process the books...
}
在这段代码中,第一个查询会检索所有作者,然后针对每个作者执行一个新查询以获取其书籍,
这样就会产生 n+1 个查询。
N+1 查询解决方案 1:急于加载
解决 n+1 查询问题的一种方法是使用一种称为急切加载(eager loading)的策略。
通过急切加载,您可以在初始查询中加载相关模型(在本例中为书籍)。
// Eager load books with authors in one query
$authors = Author::with('books')->get();
foreach($authors as $author) {
// Now, no additional query is made here
$books = $author->books;
// Process the books...
}
N+1 查询解决方案 2:联接查询
有时,您可能想使用 JOIN 语句在单个查询中获取所有内容。
https://www.w3schools.com/sql/sql_join.asp
您可以使用原始查询或框架提供的查询生成器来实现这一点。
原始查询示例(使用 PDO):
$sql = "SELECT * FROM authors JOIN books ON authors.id = books.author_id";
$stmt = $pdo->query($sql);
$authorsAndBooks = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Process the books accordingly
查询生成器示例(在 Laravel 中):
$authorsAndBooks = DB::table('authors')
->join('books', 'authors.id', '=', 'books.author_id')
->get();
// Process the results accordingly
使用原始查询或查询生成器,可以编写更优化的 SQL 查询,通过对数据库的单次请求获取所需的数据。
n+1 查询解决方案 3:缓存
解决 n+1 查询问题的另一种方法是使用缓存。
https://www.prisma.io/dataguide/managing-databases/introduction-database-caching
缓存为 n+1 查询问题提供了一种策略性解决方案,尤其是在数据变化不频繁的情况下。
通过将数据库查询结果存储在缓存中,后续请求可以从缓存中检索数据,而无需再次访问数据库。
这大大减少了对数据库的查询次数,尤其是重复请求。
需要注意的是,您可以将缓存与前一种解决方案结合使用。
PHP 中的 N+1 查询: 结论
了解并处理 n+1 查询对于优化 PHP 应用程序至关重要。
我们探讨了什么是 n+1 查询、它们如何悄无声息地降低应用程序性能,
以及使用 Scout APM 等工具检测 n+1 问题的策略。
解决 n+1 查询不仅仅是为了提高速度,而是为了编写更智能、更高效的代码。
通过应用这些见解,您可以确保为用户提供更流畅、更快速的体验。
123 在
Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..原梓番博客 在
在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..博主 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..1111 在
佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..路人 在
php中使用hyperf框架调用讯飞星火大模型实现国内版chatgpt功能示例中评论 教程很详细,如果加个前端chatgpt对话页面就完美了..Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号