当我接手一个存在性能
问题的 Laravel 应用程序时,最大的瓶颈不是代码,而是我们查询
数据库的方式。
问题
该应用程序正在加载包含相关数据的用户仪表盘,这些数据包括订单、
客户、产品和定价。每次页面加载都会触发超过 100 次数据库
查询,渲染耗时 3-5 秒。
调查
我使用 Laravel Debugbar 分析了查询语句,发现了一个典型的 N+1
问题。对于每个订单,我们都分别查询了客户数据、
产品详情和价格信息。
解决方案
第一步:预先加载
我没有采用延迟加载的方式,而是实施了策略性预先加载:
// Before: N+1 queries
$orders = Order::all();
foreach ($orders as $order) {
echo $order->customer->name; // New query each time!
}
// After: Optimized
$orders = Order::with(['customer', 'items.product'])->get();
步骤 2:查询范围
我为常见数据模式创建了可重用的查询范围:
public function scopeWithFullDetails($query) {
return $query->with([
'customer.priceList',
'items.product.category',
'payments'
]);
}
步骤 3:策略性缓存
对于访问频繁、更改很少的数据(例如产品目录),
我添加了 Redis 缓存:
$products = Cache::remember('products.catalog', 3600, function () {
return Product::with('category')->get();
});
结果
-
页面加载时间:3-5 秒 → 小于 500 毫秒 -
数据库查询:每页 100 条以上 → 每页少于 10 条 -
服务器负载显著降低 -
更好的用户体验
经验教训
- 优化之前一定要先进行性能分析
——不要靠猜测来找出瓶颈所在。 - 提前加载是好事
——但不要过度加载所有内容。 - 合理缓存
——并非所有数据都需要实时更新。 - 以关系为导向思考
——围绕数据之间的关联性来设计查询。
性能优化并非魔法——而是系统分析和
深思熟虑的解决方案。

