在 Laravel 项目中,随着流量增长,数据库查询速度变慢的情况并不少见。最近在优化一个房地产平台的后端时,我遇到了这个问题,并从中吸取了一些经验教训。
数据库优化是开发可扩展、高性能应用程序的关键领域之一。它能提升数据检索速度,从而缩短响应时间和页面加载时间,并降低服务器负载,最大限度地降低成本。
想象一下:你构建了一个出色的房地产平台,服务于多个城市,并配备了高级搜索过滤器。房产列表加载速度很快,搜索过滤器响应迅速,一切看起来都很完美。但是,随着应用程序规模的扩大和用户群的增长,那些在开发过程中表现完美的查询开始执行时间越来越长。是不是听起来很熟悉?
这正是我们平台遇到的情况。Sentry 警报在生产环境中标记了缓慢的数据库查询,这给了我们一个警醒。监控显示,搜索结果查询需要 5 秒以上才能完成——这与我们承诺的快速体验相差甚远!
还记得那些玩游戏时,击败一个敌人会产生多个较小敌人的情况吗?这与 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>
可以将数据库索引比作书的索引——它们可以帮助你找到所需内容,而无需扫描每一页。但是,索引远不止将索引添加到每一列。让我们深入探讨。
<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>
<code> // 良好:匹配查询模式 $properties = Property::where('city', 'New York') ->whereBetween('price', [200000, 500000]) ->get(); // 索引应匹配此模式 $table->index(['city', 'price']); // 首先是城市,然后是价格</code>
选择性索引 并非每一列都需要索引。选择要索引哪些列的一些指导原则包括:
监控索引使用情况
<code> -- 检查索引使用情况的 MySQL 查询 SELECT table_name, index_name, index_type, stat_name, stat_value FROM mysql.index_statistics WHERE table_name = 'properties';</code>
我见过的(以及犯过的)最常见的错误之一是默认使用 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>
处理大型数据集时,在单个操作中处理所有内容可能会压垮系统的资源并造成瓶颈。相反,可以使用 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>
缓存就像有一个能够记住一切的好助手。但是,像任何助手一样,它需要明确的指示。
<code> // 良好:匹配查询模式 $properties = Property::where('city', 'New York') ->whereBetween('price', [200000, 500000]) ->get(); // 索引应匹配此模式 $table->index(['city', 'price']); // 首先是城市,然后是价格</code>
专业提示:不要缓存所有内容!重点关注:
数据库优化不是一项可以从清单中勾选的一次性任务。它更像是照料花园——定期维护和关注才能获得最佳效果。从这些基础知识开始,监控应用程序的性能,并不断改进你的方法。
记住,目标不是实现你所知道的每种优化技术。而是要在代码可维护性和性能之间找到适合你特定用例的平衡点。有时,一个简单的预加载语句比花费数小时进行复杂的优化策略对应用程序的性能更有帮助。
你在 Laravel 项目中遇到了哪些优化挑战和/或解决了哪些问题?让我们在评论中讨论!
以上是Laravel绩效调整:优化数据库查询以进行可伸缩性的详细内容。更多信息请关注PHP中文网其他相关文章!