laravel 主表和从表一对一,从表是要多个选取最新的一条,性能优化
2025年6月10日10:35:15
Driver 模型关联方法
// 关联司机定位表
public function driverLocation()
{
return $this->hasOne(\App\Models\DriverLocation::class, 'driver_id', 'id');
}
// 关联方法
$query = Driver::with([
// 第一种常规写法
'driverLocation' => function ($query) {
$query->orderBy('id', 'desc');
},
// 第二种 减少结果集排序
'driverLocation' => function ($query) {
$query->orderBy('id', 'desc')->limit(1);
},
// 使用max子查询
'driverLocation' => function ($query) {
$query->whereIn('id', function ($sub) {
$sub->selectRaw('MAX(id)')
->from('driver_locations')
->groupBy('driver_id'); // 分组获取每组最大 id
});
}
]);
窗口函数 sql,其实性能也不好
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY driver_id
ORDER BY
id DESC -- 时间相同时取最大id(最新插入)
) AS rn
FROM driver_location
) AS ranked
WHERE rn = 1;
Driver关联 driverLocation表,driverLocation是多条,关联的是最新的一条数据的需要,但是 driverLocation有几百万条数据,所以 按照平常的写法导致性能很差
第一种,是最常见的倒序排序,在关联最新的一条,但是结果集需要排序,如果 driverLocation的数据量很大,就会很慢
第二种,是第一种的优化结果,这样就不需要吧结果集在排序,但是mysql本身会使用 ->orderBy('id', 'desc')
排序性能一般,如果 driverLocation的数据量很大,性能就一般,适合关联数据集不多的,性能就没问题
第三种,直接通过MAX函数,获取最新一条
推荐方式,这种需要确定关联最新一条的数据,如果数据量不大,那么 $query->orderBy('id', 'desc')->limit(1);
这种是最好的
如果数据量大,需要关联最新的一条,不论什么方式,性能都不太好,建议在redis存一下,这样直接去redis里取值,性能是最好的
比如这里的场景,司机定位信息,一般需要比较及时的,一般缓存一下 司机id作为key,gps信息json,作为value,有效时间为1小时
QQ一群 247823727
QQ二群 166427999
如果项目有技术瓶颈问题,请联系↓↓
QQ: 903464207
微信: zx903464207
QQ二群 166427999
如果项目有技术瓶颈问题,请联系↓↓
QQ: 903464207
微信: zx903464207