我想优化我的查询,我正在使用Laravel执行。我正在为我的项目使用MySQL,我有一个名为locations
的表。它有超过200万条记录。
当我执行下面的代码时,它太慢了。如何优化查询以提高速度?
foreach ($employees as $employee){
$percentage = 0;
if ($employee->position->zones->count() > 0) {
if($employee->position->zones->first()->workingzones->count() > 0) {
$workingZone = $employee->position->zones->first()->workingzones->last();
$tagCode = $employee->rfids->first()->rfid_id;
$zoneTime = DB::table('location')
->select(DB::raw('count(*) as count'))
->where('tagCode', $tagCode)
->where('xLocation', '>', $workingZone->x1)
->where('xLocation', '<', $workingZone->x3)
->where('yLocation', '>', $workingZone->y3)
->where('yLocation', '<', $workingZone->y1)
->where('locationDate', '>=',''.$currentDate.' 00:00:01')
->where('locationDate', '<=', $currentDate. ' 23:59:59')
->get();
$totalWorkedTime = DB::table('location')
->select(DB::raw('count(*) as count'))
->where('tagCode', $tagCode)
->where('locationDate', '>=',''.$currentDate.' 00:00:01')
->where('locationDate', '<=', $currentDate. ' 23:59:59')->get();
if ($zoneTime->first()->count == 0 || $totalWorkedTime->first()->count == 0) {
$percentage = 0;
}else {
$percentage = (int)ceil(($zoneTime->first()->count /12 )* 100 / ($totalWorkedTime->first()->count / 12));
}
}
}
$employee->percentage = $percentage;
}
答案 0 :(得分:2)
您执行完整->get()
两次,仅使用->first()
结果。当您只需要1时,只需使用->first()
代替->get()
。
此外,您可以在获取员工时加载位置和区域,并为每个循环保存2个额外查询( - 对总计分组的eagerload查询),如下所示:
$employees = Employee::where(/*where foo here*/)
->with('position.zones')
->get();
并且消耗更少的内存,将其分块。
Employee::where(/*where foo here*/)
->with('position.zones')
->chunk(200, function ($employees) {
foreach ($employees as $employee) {
// current code here with ->first() instead of ->get()
}
});
答案 1 :(得分:0)
在以下列上添加索引可以提高性能:
xLocation
yLocation
locationDate
如何使用MySQL查询添加索引: https://dev.mysql.com/doc/refman/5.7/en/create-index.html
或者如果您使用Laravel的迁移:https://laravel.com/docs/5.4/migrations#indexes
修改强>
另外:不要在两个选择查询上执行COUNT(*)
,而是使用COUNT(`id`)
,因此您不会计算所有列,只会计算id
列