为什么这个 laravel 雄辩查询运行得这么慢?
我在 Laravel 作业中运行一个查询,该查询执行速度非常慢且不一致。有时需要 1-2 分钟才能获取结果,而有时对于相同的精确查询只需 1-2 秒即可完成。
慢速完整雄辩查询(需要1-2分钟才能完成查询)
$relevantRobot = App\Robot::where('serial_number', 'TEST-ID')
->whereHas('robot_maps', function($query) use ($robot_map_name) {
$query->where('name', $robot_map_name);
})
->with(['robot_maps' => function($query) use ($robot_map_name) {
$query->where('name', $robot_map_name);
},
'current_robot_position',
'current_robot_position.robot_map',
'latest_robot_deployment_information_request'
])
->first(); // Get the raw SQL query
缓慢简化的雄辩查询(需要1-2分钟才能完成查询)
$relevantRobot = App\Robot::where('serial_number', 'TEST-ID')
->whereHas('robot_maps', function($query) use ($robot_map_name) {
$query->where('name', $robot_map_name);
})
->with(
'current_robot_position',
])
->first(); // Get the raw SQL query
快速简化的雄辩查询(不到一秒即可完成)
$relevantRobot = App\Robot::where('serial_number', 'TEST-ID')
->whereHas('robot_maps', function($query) use ($robot_map_name) {
$query->where('name', $robot_map_name);
})
->with(
'latest_robot_deployment_information_request',
])
->first(); // Get the raw SQL query
SQL 查询(不到一秒即可完成)
select * from `robots` where `serial_number` = 'TEST-ID' and exists (select * from `robot_maps` where `robots`.`id` = `robot_maps`.`robot_id` and `name` = 'test' and `active` = 1);
雄辩的关系
public function current_robot_position(){
return $this->hasOne('App\RobotMapPositionLog','robot_id','id')
->orderBy('id','desc');
}
尝试的解决方案
在注意到急切加载 current_robot_position 时加载时间较慢后,我向该关系中使用的列(id)添加了索引。然而,这并没有提高性能。
我还尝试使用 toSql() 将 Eloquent 查询转换为原始 MySQL 查询,它运行得非常快(不到 1 秒)。
出了什么问题?我错过了什么?
要提高 Laravel 查询的速度,请尝试以下步骤:
优化关系中的orderBy:使用latest('id')而不是
orderBy('id', 'desc'): 公共函数 current_robot_position() { return $this->hasOne('App\RobotMapPositionLog', 'robot_id', 'id')->latest('id'); }
添加索引:确保robot_maps和robot_map_position_logs表中的robot_id列已建立索引。
使用limit(1):直接在SQL中将主查询限制为一条记录:
->limit(1)->first();
减少嵌套关系加载:分两步加载嵌套关系,以避免额外的查询:
if ($relevantRobot) { $relevantRobot->load(['current_robot_position', 'current_robot_position.robot_map']); }
使用缓存:缓存经常访问的查询的结果,以防止重新运行查询:
Cache::remember('relevantRobot-' . $robot_map_name, now()->addMinutes(10), function() { ... });