Laravel Unique仅返回单条记录:获取操作员最新无重复作业记录
获取可用操作员的最新唯一作业记录的优化方案
问题背景
我有两张表:jobs(作业表)和operators(操作员表),它们的关联关系是:
- 一个操作员可以对应
jobs表中的多条作业记录 - 一条作业记录仅对应一个操作员
我的需求是:筛选出所有available=1(可用)的操作员,并且只保留每个操作员的最新作业记录,结果不能有重复的操作员。
目前我使用的Laravel查询代码如下:
$availableOperators = DB::table('operator') ->join('job','operator.OperatorId', '=', 'job.OperatorId') ->where('operator.available', 1) ->orderBy('job.JobId', 'desc') ->get() ->unique('job.OperatorId');
如果不添加unique('job.OperatorId')的话,我能获取到所有可用操作员的全部作业记录,但结果里每个操作员会重复出现多次,对应他们的每一条作业;加上unique()之后虽然实现了去重,但总感觉这种在应用层处理去重的方式不够高效,想请教有没有更优的数据库层面的实现方案?
优化方案:在数据库层面直接获取最新记录
你当前的写法是先把所有符合条件的作业记录查出来,再在应用层去重,当数据量较大时,会带来不必要的内存开销和性能损耗。更优的方式是直接在数据库查询阶段就筛选出每个操作员的最新作业记录,推荐两种实现方式:
方式1:使用子查询获取每个操作员的最新JobId
$availableOperators = DB::table('operator') ->join('job', function ($join) { $join->on('operator.OperatorId', '=', 'job.OperatorId') ->whereIn('job.JobId', function ($query) { $query->select(DB::raw('MAX(JobId)')) ->from('job') ->groupBy('OperatorId'); }); }) ->where('operator.available', 1) ->get();
这个写法通过子查询先找出每个操作员的最大JobId(假设JobId是自增主键,越大代表作业越新),然后再关联查询,直接得到每个操作员的最新作业记录,全程在数据库层面完成,性能更优。
方式2:使用窗口函数(适用于支持窗口函数的数据库如MySQL 8.0+、PostgreSQL等)
如果你的数据库支持窗口函数,可以用ROW_NUMBER()来实现:
$availableOperators = DB::table(function ($query) { $query->select('operator.*', 'job.*', DB::raw('ROW_NUMBER() OVER (PARTITION BY job.OperatorId ORDER BY job.JobId DESC) as rn') )->from('operator') ->join('job', 'operator.OperatorId', '=', 'job.OperatorId') ->where('operator.available', 1); }, 'sub') ->where('rn', 1) ->get();
这个方法通过窗口函数给每个操作员的作业记录按JobId倒序编号,然后只取编号为1的记录,也就是每个操作员的最新作业,逻辑清晰且性能出色。
对原写法的补充说明
如果你暂时无法使用上述优化方案,原写法也能实现需求,但需要注意:
unique('job.OperatorId')是在Laravel集合层面去重,会先加载所有符合条件的记录到内存,数据量大时会占用较多内存- 确保
JobId确实是按作业创建时间递增的,否则orderBy('job.JobId','desc')无法正确获取最新作业
内容的提问来源于stack exchange,提问作者Willower
相关产品推荐
相关产品推荐

