
本文介绍如何在 Laravel 中对关联模型数据进行多级排序,即先按整数字段(如 sort_order)升序排列,再在同一数值下按字符串字段(如 title)字母序排列,避免内存排序导致的性能与逻辑问题。
本文介绍如何在 laravel 中对关联模型数据进行多级排序,即先按整数字段(如 `sort_order`)升序排列,再在同一数值下按字符串字段(如 `title`)字母序排列,避免内存排序导致的性能与逻辑问题。
在 Laravel 开发中,常需对查询结果进行多条件排序——例如先按设备的显示顺序(device.sort_order)分组,再在每组内按部件名称(title)字母序排列。若使用 Eloquent 的 sortBy() 在集合层面处理(如 ->get()->sortBy('device.sort_order')),虽能实现初步排序,但存在明显缺陷:
- ❌ 无法真正支持二级排序:
sortBy()是 PHP 层的内存排序,不理解关联关系嵌套路径(如'device.sort_order')的语义,且对多字段组合排序无原生支持; - ❌ 性能低下:将全部数据加载到内存后排序,丧失数据库索引优势,数据量增大时响应显著变慢;
- ❌ 丢失关联预加载语义:
with('device')仅预加载关联,但sortBy('device.sort_order')实际依赖的是已加载的关联对象属性,无法触发 SQL 级联排序。
✅ 正确做法是将排序逻辑下推至数据库层,利用 SQL 的 ORDER BY sort_order, title 实现高效、准确的多级排序。对应 Laravel Eloquent 写法如下:
$parts = \App\DevicePart::with('device')
->orderBy('device.sort_order') // 注意:此处需确保 device 表字段可直接引用
->orderBy('title')
->get();⚠️ 但需注意:上述写法仅在 device.sort_order 是 DevicePart 模型自身字段时才有效。若 sort_order 实际位于关联的 devices 表中(更常见场景),则必须使用 join 或 orderByRelation(Laravel 10.28+)显式关联排序:
方案一(推荐,兼容 Laravel 8+):使用 join 显式关联并排序
$parts = \App\DevicePart::select('device_parts.*')
->join('devices', 'device_parts.device_id', '=', 'devices.id')
->with('device')
->orderBy('devices.sort_order')
->orderBy('device_parts.title')
->get();方案二(Laravel 10.28+):使用 orderByRelation(无需手动 join)
$parts = \App\DevicePart::with('device')
->orderByRelation('device', 'sort_order')
->orderBy('title')
->get();最终渲染模板时,数据已按 sort_order 升序 → 同序下 title 字母序严格排好:
@foreach($parts as $part)
{{ $part->device->sort_order }} - {{ $part->title }}
@endforeach输出效果:
1 - Baseband 1 - Carga 2 - Baseband 2 - Camera 2 - Conectores
? 关键总结:
- 始终优先在数据库层完成排序(
orderBy),而非集合层(sortBy); - 关联字段排序务必通过
join或orderByRelation显式声明,避免 N+1 或排序失效; - 确保数据库表中相关字段(如
devices.sort_order、device_parts.title)已建立适当索引(如联合索引(sort_order, title))以提升查询效率。


















