参考laravel官网文档:
https://learnku.com/docs/laravel/5.5/eloquent-relationships/1333
代码上,有大量的left join, 这时候我是想着通过mysql索引和laravel的with预加载来优化
下面给大家看看没用预加载时候的样子
public function list(Request $request)
$rows = $request->rows ?? 20;
$page = is_numeric($request->page ?? 1) ? $request->page : 1;
$sql = HandworkOrders::where('m_handwork_orders.status' , '<>' , -1)->select([
'm_handwork_orders.*',
'm_users.name' ,
'm_third_party_users.nickname' ,
'm_goods.name as goods_name' ,
'm_users.head_img' ,
'm_third_party_users.head_img as third_head_img',
'm_admin_users.nickname as admin_name',
'uu.name as donor_name',
'uu.head_img as donor_head_img',
'up.nickname as donor_third_name',
'up.head_img as donor_third_head_img'
])->distinct('m_handwork_orders.transfer_no');
$sql = $sql->leftjoin( 'm_users' , 'm_handwork_orders.user_id', '=', 'm_users.id');
$sql = $sql->leftjoin( 'm_users as uu' , 'uu.id' , '=' , 'm_handwork_orders.donor_user_id');
$sql = $sql->leftjoin( 'm_third_party_users' , 'm_third_party_users.id' , '=' , 'm_users.third_party_user_id');
$sql = $sql->leftjoin( 'm_third_party_users as up' , 'up.id' , '=' , 'uu.third_party_user_id');
$sql = $sql->leftjoin( 'm_goods' , function($join){
$join->on('m_goods.sku' , '=' , 'm_handwork_orders.sku')
->where('m_goods.status' , '<>' , -1);
$sql = $sql->leftjoin( 'm_admin_users' , 'm_admin_users.id' , '=' , 'm_handwork_orders.admin_id');
if($request->user_id){
$sql = $sql->where('m_handwork_orders.user_id' , $request->user_id);
if($request->sku){
$sql = $sql->where('m_handwork_orders.sku' , $request->sku);
if($request->donor_user_id){
$sql = $sql->where('m_handwork_orders.donor_user_id' , $request->donor_user_id);
if($request->user_mobile){
$sql = $sql->where('m_users.mobile' , $request->user_mobile);
if($request->donor_user_mobile){
$sql = $sql->where('uu.mobile' , $request->donor_user_mobile);
if($request->startDate){
$sql = $sql->where('m_handwork_orders.created_at' , '>=' , $request->startDate);
if($request->endDate){
$sql = $sql->where('m_handwork_orders.created_at' , '<=' , $request->endDate);
$count = $sql->count();
$sql = $sql->skip( ($page - 1) * $rows )->take($rows)->orderBy(request('sort'), request('sortOrder'));
return response()->json([
'total' => $count,
'rows' => $sql->get()
这里面有七个left join ,说到这个,有人会说left join 会比预加载快
我个人认为,各有优点,预加载,他的原理就是通过in 来做where的,如果数据量比较大,当然是不推荐使用预加载。因为你可以想想
那么多 id 去 where in 这当然是不可取的,这时候就要考虑用left join 了,但是left join 也不能太依赖,下面我来给大家看看 他的原理
参考文章:https://www.jianshu.com/p/16ad9669d8a9
图片中,说到多次回表查询,然后再看看我上面的这串代码,有7个left join 呢,说明什么?7次回表查询,这样的效率是非常慢的
left join 越多,回表的次数是不是就越多了,效率是不是会更慢。如果是join 会更慢,为什么呢?因为底层匹配到了数据之后,还要做拼接,再根据你想要的结果返回给你。
这时候我就考虑了用with预加载了,一般查询量没有一万几万的,都是with预加载比较占优势的。
public function getListTest(Request $request)
$rows = $request->rows ?? 20;
$page = is_numeric($request->page ?? 1) ? $request->page : 1;
$handworkOrders = new HandworkOrders();
if($request->user_id){
$handworkOrders = $handworkOrders->where('m_handwork_orders.user_id' , $request->user_id);
if($request->sku){
$handworkOrders = $handworkOrders->where('m_handwork_orders.sku' , $request->sku);
if($request->donor_user_id){
$handworkOrders = $handworkOrders->where('m_handwork_orders.donor_user_id' , $request->donor_user_id);
if($request->user_mobile){
$user_mobile = $request->user_mobile;
$handworkOrders = $handworkOrders->whereHas('getUsers',function($req) use($user_mobile) {
$req->where('mobile', $user_mobile);
if($request->donor_user_mobile){
$donor_user_mobile = $request->donor_user_mobile;
$handworkOrders = $handworkOrders->whereHas('getUsersUparam',function($req) use($donor_user_mobile) {
$req->where('mobile', $donor_user_mobile);
if($request->startDate){
$handworkOrders = $handworkOrders->where('m_handwork_orders.created_at' , '>=' , $request->startDate);
if($request->endDate){
$handworkOrders = $handworkOrders->where('m_handwork_orders.created_at' , '<=' , $request->endDate);
if ($request->input('sort', '') && $request->input('sortOrder', '')) {
$handworkOrders = $handworkOrders->orderBy($request->input('sort'),$request->input('sortOrder'));
// 预加载 with
$data = $handworkOrders->with([
'getAdminUsers:nickname,id',// 操作人信息
'getUsers:name as user_name,head_img as user_head_img,id,third_party_user_id',// 用户信息(获益者)
'getUsers.getThirdPartyUsers:nickname as t_nickname,head_img as t_head_img,id',// 用户信息(获益者) 第三方数据
'getUsersUparam:name as uname,head_img as uhead_img,id,third_party_user_id',// 赠送者用户表信息
'getUsersUparam.getThirdPartyUsers:nickname as tpnickname,head_img as tphead_img,id',// 赠送者第三方表信息
'getGoods:name as goods_name,sku',// 商品信息
->where('status', '<>', -1)
->skip( ($page - 1) * $rows )
->take($rows)
->get([
'id',
'goods_price',
'user_id',
'donor_user_id',
'sku',
'admin_id',
'amount',
'remarks',
'transfer_no',
'created_at',
$count = $handworkOrders->count();
$lists = collect($data)->map(function($item) {
// 用户信息 (获益者)
if (isset($item->getUsers) && $item->getUsers) {
$item->name = $item->getUsers->user_name ?? '';
$item->head_img = $item->getUsers->user_head_img ?? '';
// 用户第三方 (获益者)
if (isset($item->getUsers->getThirdPartyUsers) && $item->getUsers->getThirdPartyUsers) {
$item->nickname = $item->getUsers->getThirdPartyUsers->t_nickname ?? '';
$item->third_head_img = $item->getUsers->getThirdPartyUsers->t_head_img ?? '';
// 赠送者
if (isset($item->getUsersUparam) && $item->getUsersUparam) {
$item->donor_name = $item->getUsersUparam->uname ?? '';
$item->donor_head_img = $item->getUsersUparam->uhead_img ?? '';
// 赠送者第三方
if (isset($item->getUsersUparam->getThirdPartyUsers) && $item->getUsersUparam->getThirdPartyUsers) {
$item->donor_third_name = $item->getUsersUparam->getThirdPartyUsers->tpnickname ?? '';
$item->donor_third_head_img = $item->getUsersUparam->getThirdPartyUsers->tphead_img ?? '';
// 商品
if (isset($item->getGoods) && $item->getGoods) {
$item->goods_name = $item->getGoods->goods_name ?? '';
$item->sku = $item->sku ?? '';
// 操作人
if (isset($item->getAdminUsers) && $item->getAdminUsers) {
$item->admin_name = $item->getAdminUsers->nickname ?? '';
unset($item->getUsers);
unset($item->getUsersUparam);
unset($item->getGoods);
unset($item->getAdminUsers);
return $item;
})->toArray();
return response()->json([
'total' => $count,
'rows' => $lists
model类
namespace App\Repositories;
use Illuminate\Database\Eloquent\Model;
class HandworkOrders extends Model
protected $table = 'm_handwork_orders';
protected $guarded = [];
* 赠送者信息
* @return \Illuminate\Database\Eloquent\Relations\HasOne
public function getUsers()
return $this->hasOne(User::class, 'id', 'user_id');
* 获益者信息
* @return \Illuminate\Database\Eloquent\Relations\HasOne
public function getUsersUparam()
return $this->hasOne(User::class, 'id', 'donor_user_id');
* sku获取goods
* @return \Illuminate\Database\Eloquent\Relations\HasOne
public function getGoods()
return $this->hasOne(Goods::class, 'sku', 'sku')
->where('status', '<>', -1);
* 管理员信息
* @return \Illuminate\Database\Eloquent\Relations\HasOne
public function getAdminUsers()
return $this->hasOne(AdminUser::class, 'id', 'admin_id');
你要必须保证,每个表都有用到索引,我这里是都用上了索引
with([
'getAdminUsers:nickname,id',// 操作人信息
'getUsers:name as user_name,head_img as user_head_img,id,third_party_user_id',// 用户信息(获益者)
'getUsers.getThirdPartyUsers:nickname as t_nickname,head_img as t_head_img,id',// 用户信息(获益者) 第三方数据
'getUsersUparam:name as uname,head_img as uhead_img,id,third_party_user_id',// 赠送者用户表信息
'getUsersUparam.getThirdPartyUsers:nickname as tpnickname,head_img as tphead_img,id',// 赠送者第三方表信息
'getGoods:name as goods_name,sku',// 商品信息
getUsersUparam:name as uname,head_img as uhead_img,id,third_party_user_id
getUsersUparam 是模型里面的方法
name as uname,head_img as uhead_img,id,third_party_user_id 是字段,他们通过逗号分隔开
特别要注意的是,关联的关键字段,必须要select出来,不然是查不到的,因为它底层是要获取你关联的字段去where in 的
如果你想获取关联模型里面的关联模型,就这样写:
getUsers.getThirdPartyUsers
下面的whereHas 是对模型里面的一对一方法,进行where条件搜索之类的,会约束到整个查询哦~
好比如,你查询的是mobile = 12311231 也就是说,你整个查询,都会受约束,只要getUsersUparam这个一对一方法里面,没有mobile=12311231,那么你这一整个查询会返回null,也就是说你这个列表没有数据返回的。
if($request->donor_user_mobile){
$donor_user_mobile = $request->donor_user_mobile;
$handworkOrders = $handworkOrders->whereHas('getUsersUparam',function($req) use($donor_user_mobile) {
$req->where('mobile', $donor_user_mobile);
with()
with()方法是用作“渴求式加载”的,那主要意味着,laravel将会伴随着主要模型预加载出确切的的关联关系。这就对那些如果你想加在一个模型的所有关联关系非常有帮助。因为“渴求式加载”缓解了1+N的查询问题,仅需1+1次查询就能解决问题,对查询速度有了质的提升。
has()
has()方法是基于关联关系去过滤模型的查询结果,所以它的作用和where条件非常相似。如果你只使用has('post'),这表示你只想得到这个模型,这个模型的至少存在一个post的关联关系。
whereHas()
whereHas()方法的原理基本和has()方法相同,但是他允许你自己添加对这个模型的过滤条件。
优化前和优化后对比图,一般一页不要让管理员查询那么多,一般100条足够了,建议最大到500条一页就好了,看公司业务
代码上,有大量的left join, 这时候我是想着通过mysql索引和laravel的with预加载来优化下面给大家看看没用预加载时候的样子public function list(Request $request){ $rows = $request->rows ?? 20; $page = is_numeric($request->page ...
laravel 使用with预加载(渴求加载)的使用方法示例with()方法能做什么?在什么场景使用?表结构代码实现(根据当前登录用户,获取用户下的所有相关文章)
with()方法能做什么?在什么场景使用?
1.情景如下。2张数据表 主表userinfors用户表【id,name,created_at】,从表文章表articles表【id,user_id,title,content,created_at】
3.需求:根据当前登录用户A获取A所发布的文章。
4.模型之间的关系:一对多,一个用户能有多篇文章。
gorm 一对多关系 以及预加载的用法一对多关系的介绍预加载Preload预加载不使用预加载使用预加载使用链式预加载条件预加载Joins 预加载
一对多关系的介绍
这里女神表里面有多个舔狗,就是一对多has many关系
并且舔狗表里面包含Info信息表,是has one关系
type GirlGOD struct {
gorm.Model
Name string
Dog []Dog
type Dog struct {
gorm.Model
Name string
GirlGo
文章目录关联分类重写外键、引用多态关联外键约束关联操作自动添加关联关联模式查询关联添加关联替换关联删除关联级联删除清空关联关联计数批量处理数据预加载Preload带条件的预加载预加载全部自定义预加载 SQL嵌套预加载Joins预加载
belongs to:会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。比如:一个学员属于一个门派
has one:与另一个模型建立一对一的关联,但它和一对一关系有些许不同。 这种关联表明一个模型的每个实例都包含或拥有另一个模
通常情况下我们在做leftjoin连接时需要对不止一个条件进行进行匹配,这时候就需要使用闭包方式,如下:
leftjoin('db', function ($join) {···});
leftjoin多条件查询,无非以下三种情况。
并且关系(&&)且为字段名称,使用on,代码示例如下:
$roomUuid = 1;
$chatInfo ...
$v = '28';
$data = DB::table('admin_users AS au')
->leftJoin('company AS c','au.company','=','c.id')
->where('admin_use...
解决问题:Fatal error: Uncaught Swoole\Exception: Swoole\Http\Server can only be used in CLI mode in
mongodb分页排序问题 Sort exceeded memory limit of 104857600 bytes, but did not opt in to external sorting.