上一篇
最近接手了一个电商后台项目,产品列表页加载慢得像蜗牛🐌,用户吐槽说:"点个分类筛选要等3秒,隔壁家某宝都是秒开的!" 😤 一查数据库日志,发现居然有500+次查询!这不就是传说中的N+1查询问题吗?
假设我们要显示一个订单列表,每个订单需要展示用户昵称,初学者的写法可能是这样的:
// 💀 错误示范:N+1查询的罪魁祸首 $orders = Order::all(); foreach ($orders as $order) { echo $order->user->nickname; // 每个订单都发起一次用户查询! }
当有100个订单时,实际会执行101次查询(1次查订单+100次查用户)!这就是臭名昭著的N+1问题。
Laravel的with
方法就是来解决这个问题的!看这个魔法:
// ✅ 正确示范:2次查询解决所有数据 $orders = Order::with('user')->get(); foreach ($orders as $order) { echo $order->user->nickname; // 直接从预加载的数据中取 }
执行过程:
IN
语句一次性查出所有关联的用户SELECT * FROM users WHERE id IN (1,2,3,4,5...)
有时候我们不需要关联模型的全部字段,比如只需要用户的id
和nickname
,这时候可以这样写:
$orders = Order::with(['user' => function ($query) { $query->select('id', 'nickname'); // 只查这两个字段 }])->select('id', 'user_id', 'amount')->get();
好处:
// 控制器代码 public function index() { $orders = Order::paginate(10); // 1次查询 return view('orders.index', compact('orders')); } // 视图代码 @foreach ($orders as $order) <tr> <td>{{ $order->id }}</td> <td>{{ $order->user->nickname }}</td> <!-- 每次循环都查用户 --> <td>{{ $order->amount }}</td> </tr> @endforeach
问题:每页10条数据,实际执行11次查询!
// 控制器代码 public function index() { $orders = Order::with(['user' => function ($query) { $query->select('id', 'nickname'); }])->select('id', 'user_id', 'amount') ->paginate(10); // 2次查询搞定 return view('orders.index', compact('orders')); }
执行过程:
user_id
)id
和nickname
MySQL 8.0.18+ 默认启用哈希连接,处理大数据量时比传统嵌套循环快10倍+!
-- 自动使用哈希连接 EXPLAIN SELECT * FROM orders JOIN users ON orders.user_id = users.id;
复合索引:经常一起查询的字段建复合索引
ALTER TABLE orders ADD INDEX idx_user_amount (user_id, amount);
覆盖索引:让查询直接从索引取数据
-- 创建覆盖索引 ALTER TABLE users ADD INDEX idx_nickname (id, nickname);
始终使用with预加载关联数据
// 多关联场景 $posts = Post::with(['author', 'comments.user'])->get();
指定字段查询
// 限制主模型字段 $users = User::select('id', 'name')->with(['orders' => function ($q) { $q->select('id', 'user_id', 'amount'); }])->get();
结合MySQL新特性
善用工具
EXPLAIN ANALYZE
分析执行计划场景 | 优化前耗时 | 优化后耗时 | 提升幅度 |
---|---|---|---|
100条订单列表 | 1280ms | 210ms | 610% |
500条关联数据导出 | 4520ms | 890ms | 509% |
复杂多表关联查询 | 2350ms | 420ms | 558% |
优化后的订单列表页加载时间从3秒降到0.6秒,用户直呼:"这速度,比某宝还快!" 🚀
💡 小贴士:2025年Laravel 12.x已经完美支持PHP 8.3的JIT加速,配合MySQL 8.0的优化器,中小型项目基本可以告别数据库瓶颈!
现在就去给你的项目做个体检吧!用上这些技巧,让你的Laravel应用飞起来~ 🛩️
本文由 业务大全 于2025-08-25发表在【云服务器提供商】,文中图片由(业务大全)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://cloud.7tqx.com/wenda/729391.html
发表评论