首页 > 后端开发 > php教程 > Laravel绩效调整:优化数据库查询以进行可伸缩性

Laravel绩效调整:优化数据库查询以进行可伸缩性

Barbara Streisand
发布: 2025-01-30 06:04:13
原创
680 人浏览过

Laravel Performance Tuning: Optimizing Database Queries for Scalability

在 Laravel 项目中,随着流量增长,数据库查询速度变慢的情况并不少见。最近在优化一个房地产平台的后端时,我遇到了这个问题,并从中吸取了一些经验教训。

数据库优化是开发可扩展、高性能应用程序的关键领域之一。它能提升数据检索速度,从而缩短响应时间和页面加载时间,并降低服务器负载,最大限度地降低成本。

房地产平台的挑战

想象一下:你构建了一个出色的房地产平台,服务于多个城市,并配备了高级搜索过滤器。房产列表加载速度很快,搜索过滤器响应迅速,一切看起来都很完美。但是,随着应用程序规模的扩大和用户群的增长,那些在开发过程中表现完美的查询开始执行时间越来越长。是不是听起来很熟悉?

这正是我们平台遇到的情况。Sentry 警报在生产环境中标记了缓慢的数据库查询,这给了我们一个警醒。监控显示,搜索结果查询需要 5 秒以上才能完成——这与我们承诺的快速体验相差甚远!

常见的查询缺陷(以及如何避免)

1. N 1 查询问题:数据库的秘密敌人

还记得那些玩游戏时,击败一个敌人会产生多个较小敌人的情况吗?这与 Laravel 中的 N 1 查询问题本质上是一样的。你获取房产列表,然后为每个房产进行额外的查询以获取相关数据。在你意识到之前,你的数据库正在处理数百个查询,而不是只有一个。

以下是它的典型表现:

<code>// 优化前
$properties = Property::all();
foreach ($properties as $property) {
    echo $property->agent->name;  // 每个房产都会触发一个新的查询
}

// 优化后
// 使用 `with()` 进行预加载
$properties = Property::with(['agent'])->get();
foreach ($properties as $property) {
    echo $property->agent->name;  // 不需要额外的查询!
}</code>
登录后复制
登录后复制

2. 数据库索引的艺术

可以将数据库索引比作书的索引——它们可以帮助你找到所需内容,而无需扫描每一页。但是,索引远不止将索引添加到每一列。让我们深入探讨。

理解不同类型的索引

<code>// 基本的单列索引
Schema::table('properties', function (Blueprint $table) {
    $table->index('price');
});

// 多列的组合索引
Schema::table('properties', function (Blueprint $table) {
    $table->index(['city', 'price']); // 顺序很重要!
});

// 唯一索引
Schema::table('properties', function (Blueprint $table) {
    $table->unique('property_code');
});</code>
登录后复制
登录后复制

索引策略最佳实践

  1. 组合索引中的列顺序很重要
<code>   // 良好:匹配查询模式
   $properties = Property::where('city', 'New York')
                        ->whereBetween('price', [200000, 500000])
                        ->get();

   // 索引应匹配此模式
   $table->index(['city', 'price']); // 首先是城市,然后是价格</code>
登录后复制
登录后复制
  1. 选择性索引 并非每一列都需要索引。选择要索引哪些列的一些指导原则包括:

    • 索引在 WHERE 子句和 ORDER BY 语句中经常使用的列
    • 索引外键列
    • 不要索引选择性低的列(例如布尔标志)
  2. 监控索引使用情况

<code>   -- 检查索引使用情况的 MySQL 查询
   SELECT
       table_name,
       index_name,
       index_type,
       stat_name,
       stat_value
   FROM mysql.index_statistics
   WHERE table_name = 'properties';</code>
登录后复制

3. 只选择你需要的内容,而不是所有内容

我见过的(以及犯过的)最常见的错误之一是默认使用 select *。这就像去杂货店购物,却买下整个商店的东西,而你只需要一顿饭的食材。以下是一种更好的方法:

<code>// 优化前
$properties = Property::all();
foreach ($properties as $property) {
    echo $property->agent->name;  // 每个房产都会触发一个新的查询
}

// 优化后
// 使用 `with()` 进行预加载
$properties = Property::with(['agent'])->get();
foreach ($properties as $property) {
    echo $property->agent->name;  // 不需要额外的查询!
}</code>
登录后复制
登录后复制

4. 用于大型数据集的分块处理

处理大型数据集时,在单个操作中处理所有内容可能会压垮系统的资源并造成瓶颈。相反,可以使用 Laravel 的 chunk 方法以可管理的批次处理记录:

<code>// 基本的单列索引
Schema::table('properties', function (Blueprint $table) {
    $table->index('price');
});

// 多列的组合索引
Schema::table('properties', function (Blueprint $table) {
    $table->index(['city', 'price']); // 顺序很重要!
});

// 唯一索引
Schema::table('properties', function (Blueprint $table) {
    $table->unique('property_code');
});</code>
登录后复制
登录后复制

5. 切实有效的缓存策略

缓存就像有一个能够记住一切的好助手。但是,像任何助手一样,它需要明确的指示。

<code>   // 良好:匹配查询模式
   $properties = Property::where('city', 'New York')
                        ->whereBetween('price', [200000, 500000])
                        ->get();

   // 索引应匹配此模式
   $table->index(['city', 'price']); // 首先是城市,然后是价格</code>
登录后复制
登录后复制

专业提示:不要缓存所有内容!重点关注:

  • 经常访问的数据
  • 计算成本高的数据
  • 不经常更改的数据

最佳实践

  1. 先监控,后优化 不要陷入过早优化的陷阱。使用 Laravel 内置的查询日志或 Telescope 等工具来识别实际的瓶颈。
  2. 以集合思考,而不是循环 每当你发现自己编写了一个查询数据库的 foreach 循环时,请退一步,问问自己是否有一种方法可以用单个查询来处理它。
  3. 策略性地缓存 并非所有内容都需要缓存。关注经常访问的、计算成本高的查询,这些查询不需要实时准确性。
  4. 深思熟虑地创建索引 将索引视为书的目录——你需要足够的细节才能快速找到东西,但不要太多以至于目录比书本身还长。

需要避免的常见缺陷

  • 不要“预加载”不需要的关系
  • 避免在循环中运行查询(伪装的 N 1 问题的陷阱)
  • 不要缓存所有内容——有时缓存管理的开销超过了好处
  • 对大型数据集中的非索引列使用 orderBy 时要小心
  • 不要为在 WHERE 子句中很少使用的列创建索引
  • 避免频繁更新索引列;每次更新都需要索引维护

结论:这是一个旅程,而不是目的地

数据库优化不是一项可以从清单中勾选的一次性任务。它更像是照料花园——定期维护和关注才能获得最佳效果。从这些基础知识开始,监控应用程序的性能,并不断改进你的方法。

记住,目标不是实现你所知道的每种优化技术。而是要在代码可维护性和性能之间找到适合你特定用例的平衡点。有时,一个简单的预加载语句比花费数小时进行复杂的优化策略对应用程序的性能更有帮助。

你在 Laravel 项目中遇到了哪些优化挑战和/或解决了哪些问题?让我们在评论中讨论!

以上是Laravel绩效调整:优化数据库查询以进行可伸缩性的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板