如何高效检索关联工时完成率≥80%的Order数据?
最优高效的Order检索方案
嘿,针对你这个需求,最靠谱且高效的做法是让数据库直接完成聚合和筛选逻辑,避免把所有数据拉到应用层再处理(那样会有N+1查询和不必要的内存开销)。下面分两种常用的实现方式给你说明:
一、原生Join查询(性能最优)
这种方式用单条SQL查询完成所有操作,直接从数据库返回符合条件的Order,是大数据量场景下的首选:
$qualifiedOrders = Order::query() // 关联Order和对应的ConstructionSite ->join('construction_sites', 'orders.id', '=', 'construction_sites.order_id') // 关联ConstructionSite对应的所有WorkingHours ->join('working_hours', 'construction_sites.id', '=', 'working_hours.construction_site_id') // 选择Order的所有字段,同时计算总工时 ->select('orders.*') ->selectRaw('SUM(working_hours.worked_hours) as total_worked_hours') // 按Order分组,确保每个Order只计算一次总工时 ->groupBy('orders.id') // 筛选总工时达到计划工时80%的Order ->havingRaw('total_worked_hours >= orders.installation_planned_in_hours * 0.8') ->get();
为什么高效?
- 所有计算和筛选都在数据库端完成,只返回符合条件的数据,减少了应用层和数据库之间的数据传输。
- 避免了循环遍历每个Order再查询关联数据的N+1问题,单次查询就能搞定。
二、Eloquent关联语法(更贴合ORM风格)
如果你更习惯用Eloquent的关联写法,也可以结合withSum和whereHas实现,代码更直观:
$qualifiedOrders = Order::query() // 预加载关联的总工时(避免N+1) ->withSum('constructionSite.workingHours', 'worked_hours') // 筛选满足条件的Order ->whereHas('constructionSite.workingHours', function ($query) { $query->groupBy('construction_site_id') ->havingRaw('SUM(worked_hours) >= (SELECT installation_planned_in_hours FROM orders WHERE id = construction_sites.order_id) * 0.8'); }) ->get();
注意事项
为了让查询跑得更快,一定要给这些字段加索引:
construction_sites.order_id(Order和ConstructionSite的关联键)working_hours.construction_site_id(ConstructionSite和WorkingHours的关联键)
索引能大幅提升关联查询的效率,尤其是数据量较大时。
另外,确保你的模型关联关系定义正确:
- Order模型:
public function constructionSite() { return $this->hasOne(ConstructionSite::class); }
- ConstructionSite模型:
public function order() { return $this->belongsTo(Order::class); } public function workingHours() { return $this->hasMany(WorkingHours::class); }
- WorkingHours模型:
public function constructionSite() { return $this->belongsTo(ConstructionSite::class); }
内容的提问来源于stack exchange,提问作者Dim13i
相关产品推荐
相关产品推荐

