Laravel如何获取两张关联数据表的最新5条记录?
现有方案的不足
- 多表查询时SQL查询次数随接入表数量线性增长,额外增加数据库压力
- 需在PHP层面对多集合合并后排序,数据量变大后排序性能会明显下降
- 后续新增数据表时需要重复编写查询逻辑,代码复用性差
优化方案
方案1:SQL层UNION ALL一次查询(推荐)
直接在数据库层面合并两个表的查询结果并排序取数,仅执行1次SQL,性能最优,适合所有接入表的展示字段可统一的场景。
Laravel 实现代码示例:
$shopId = 1; // 构造orders查询,统一字段格式,加type标识数据类型 $ordersQuery = DB::table('orders') ->select( 'id', DB::raw("'order' as type"), 'created_at', // 统一要展示的其他字段,不存在的字段可以补空值对齐 DB::raw('null as birthday_content') ) ->where('shop_id', $shopId); // 构造collected_birthdays查询,字段和上面的查询完全对齐 $birthdaysQuery = DB::table('collected_birthdays') ->select( 'id', DB::raw("'collected_birthday' as type"), 'created_at', 'content as birthday_content' ) ->where('shop_id', $shopId); // 合并查询结果、排序、直接取前5条 $latestActivity = $ordersQuery->unionAll($birthdaysQuery) ->orderBy('created_at', 'desc') ->limit(5) ->get();
如果需要用到模型的关联属性,可以拿到查询结果后再对应加载对应模型的关联数据即可。
方案2:可扩展的多集合查询封装
如果不同表的字段差异极大,不方便在SQL层做UNION对齐,可以封装公共逻辑适配后续多表接入的需求:
class LatestActivityService { // 新增表仅需在此处添加对应模型关联方法名即可 protected $activityRelations = [ 'orders', 'collectedBirthdays', // 后续新增表直接加对应关联名 // 'otherTableRelation' ]; public function getLatest(Shop $shop, int $limit = 5) { $collections = collect(); foreach ($this->activityRelations as $relation) { $collections = $collections->merge( $shop->$relation()->orderBy('created_at', 'desc')->limit($limit)->get() ); } return $collections->sortByDesc('created_at')->take($limit); } } // 调用方式 $shop = Shop::FindOrFail(1); $latestActivity = app(LatestActivityService::class)->getLatest($shop, 5);
选型建议
- 单店单表数据量小于10万,且接入表数量少于5个的情况下,两种方案性能差异不大,优先选方案2,开发更灵活
- 数据量大或者接入表多的场景,优先选方案1,减少数据库查询次数和PHP层面的计算开销
内容的提问来源于stack exchange,提问作者ViktorasssIT
相关产品推荐
相关产品推荐

