[扩展包] Laravel-wherehasin 提升 ORM 关联关系查询性能 (优化 whereHas 性能)
前言
前几天在QQ群里看到有位同学请人帮忙根据社区里的文章(给 Eloquent 的 whereHas 加个 where in 的优化)给Eloquent
的whereHas
方法进行性能优化,因为这篇文章里面提供的代码还是有些细节问题,并不能支持所有的关联关系,所以我抽空写了这个扩展包,支持了所有关联关系。并且我也做了一些小测试,发现在数据量大的情况下优化过后的性能提升非常惊人,下面是一个简单的测试,如果有不正确之处欢迎大家拍砖指正:
主表test_users
写入130002
条数据,关联表test_user_profiles
写入1002
条数据,查询代码如下
<?php
/**
* 未优化sql
*
* select * from `test_users` where exists
* (
* select * from `test_user_profiles`
* where `test_users`.`id` = `test_user_profiles`.`user_id`
* )
* limit 10
*/
$users1 = User::whereHas('profile')->limit(10)->get();
/**
* 优化后的sql
*
* select * from `test_users` where `test_users`.`id` in
* (
* select `test_user_profiles`.`user_id` from `test_user_profiles`
* where `test_users`.`id` = `test_user_profiles`.`user_id`
* )
* limit 10
*/
$users1 = User::whereHasIn('profile')->limit(10)->get();
最终耗时如下,可以看出性能相差还是不小的,如果数据量更多一些,这个差距还会更大
whereHas (优化前) 0.50499701499939 秒
whereHasIn (优化后) 0.027166843414307 秒
多测试几次之后不难发现:
当主表数据量较多的情况下,where id in会有明显的性能提升;当主表数据量较少的时候,两者性能相差无几。
简介
Laravel wherehasin
是一个可以提升Laravel ORM
关联关系查询性能的扩展包,可以替代Laravel ORM
中的whereHas
以及whereHasMorphIn
查询方法。
Github (如果喜欢这个项目不妨点个star,谢谢支持~)
环境
- PHP >= 7
- laravel >= 5.5
安装
composer require dcat/laravel-wherehasin
使用
whereHasIn
此方法已支持Laravel ORM
中的所有关联关系,可以替代whereHas
User::whereHasIn('profile')->get();
User::whereHasIn('profile', function ($q) {
$q->where('id', '>', 10);
})->get();
orWhereHasIn
User::where('name', 'like', '%laravel%')->orWhereHasIn('profile')->get();
多级关联关系
User::whereHasIn('painters.paintings', function ($q) {
$q->whereIn('id', [600, 601]);
})->orderBy('id')->get()->toArray();
需要注意的是,如果是BelongsTo
类型的关联关系,使用whereHasIn
时使用的不是主键,而是外键
<?php
/**
* 这里用的是"user_id in",而不是"id in"
*
* select * from `test_user_profiles` where `test_user_profiles`.`user_id` in
* (
* select `test_users`.`id` from `test_users` where `test_user_profiles`.`user_id` = `test_users`.`id`
* )
*/
$profiles = Profile::whereHasIn('user')->get();
whereHasMorphIn
此方法已支持Laravel ORM
中的所有关联关系,可以替代whereHasMorph
Image::whereHasMorphIn('imageable', Post::class, function ($q) {
$q->where('id', '>', 10);
})->get();
鸣谢
给 Eloquent 的 whereHas 加个 where in 的优化
附
评论区下面有同学留言说当副表数据过大时mysql可能会报错,所以我增加了一个小测试,主表写入50W数据,副表写入100W数据,结论是副表数据过大时也影响不大,
使用whereHasIn
耗时 0.335 秒
User::query()->whereHasIn('profile')->count();
如果是whereHas
则页面直接卡死了,等了十几分钟都出不来结果
User::query()->whereHas('profile')->count();
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: