我有一个带有过滤器的车辆列表页面。我已经创建了一个将所选过滤器应用于车辆表的范围。范围使用雄辩的whereHas方法。但是在执行查询时会出现严重的性能问题,因为我将每个whereHas转换为子查询而不是Join。请参阅下面的范围函数和查询运行

public function scopeApplyFilter($query, $conditions, $featured=0)
{

    $query->where(function($q) use ($conditions){
        if ($conditions->get('content')) {
            $q->where('text', 'like', '%'.$conditions->get('content').'%' );
        }
        if ($conditions->get('condition')) {
            $q->where('condition', $conditions->get('condition'));
        }
        if ($conditions->get('transmission')) {
            $q->where('transmission', $conditions->get('transmission'));
        }
        if ($conditions->get('price')) {
            $range = explode('-', $conditions->get('price'));

            $q->where('price', '>=',$range[0]);
            $q->where('price', '<=',$range[1]);
        }
        if ($conditions->get('odometer')) {
            $range = explode('-', $conditions->get('odometer'));

            $q->where('odometer', '>=',$range[0]);
            $q->where('odometer', '<=',$range[1]);
        }
        if ($conditions->get('year')) {
            $range = explode('-', $conditions->get('year'));

            $q->where('year', '>=',$range[0]);
            $q->where('year', '<=',$range[1]);
        }

        return $q;
    })->whereHas('model', function($q) use ($conditions) {
        if ($conditions->get('model')) {
            $q->where('model_name', $conditions->get('model'));
        }
        return $q;
    })->whereHas('make', function($q) use ($conditions) {
        if ($conditions->get('make')) {
            $q->where('make_name', $conditions->get('make'));
        }
        return $q;
    })->whereHas('dealer.province', function($q) use ($conditions) {
        if ($conditions->get('province')) {
            $q->where('province_name', $conditions->get('province'));
        }
        return $q;
    })->whereHas('dealer', function($q) use ($conditions, $featured) {
        if($featured){
            $q->where('featured', 1);
        }
        if ($conditions->get('lat')) {
            //$conditions->put('distance',5000);
            $lat = $conditions->get('lat');
            $lon = $conditions->get('lon');
            $lat = 53.421879;
            $lon = -113.4675614;
            $q->select(DB::raw("id, ( 6371 * acos( cos( radians($lat) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians($lon) ) + sin( radians($lat) ) * sin( radians( latitude ) ) ) ) AS distance"))->having('distance','<',$conditions->get('distance')); //3959 for miles
        }
        return $q;
    });
}

查询运行是

SELECT * 
FROM   `vehicles` 
WHERE  EXISTS (SELECT * 
               FROM   `models` 
               WHERE  `vehicles`.`model_id` = `models`.`id`) 
   AND EXISTS (SELECT * 
               FROM   `makes` 
               WHERE  `vehicles`.`make_id` = `makes`.`id`) 
   AND EXISTS (SELECT * 
               FROM   `dealers` 
               WHERE  `vehicles`.`dealer_id` = `dealers`.`id` 
                      AND EXISTS (SELECT * 
                                  FROM   `provinces` 
                                  WHERE  `dealers`.`province_id` = 
                                 `provinces`.`id`)) 
   AND EXISTS (SELECT id, 
                      ( 6371 * Acos(Cos(Radians(53.421879)) * 
                                    Cos(Radians(latitude)) * 
                                    Cos( 
                                                  Radians(longitude) 
                                                  - Radians( 
                                                  -113.4675614)) 
                                    + 
                                             Sin(Radians(53.421879)) * 
                                             Sin(Radians(latitude))) 
                                 ) AS 
                      distance 
               FROM   `dealers` 
               WHERE  `vehicles`.`dealer_id` = `dealers`.`id` 
               HAVING `distance` < 200) 
   AND `status_id` = 1 
ORDER  BY `created_at` DESC 
LIMIT  15 offset 0 

501.16 ms

我使用的是Laravel 5.2。制造商,型号和经销商是车辆的“属于”关系。一切都很好 但是由于性能问题,我被迫使用连接重写功能。请帮助最佳做法使用基于上述条件的连接重写此功能。您的投入是最受欢迎的。
 

 

所有列是否正确索引? -  罗斯·威尔逊 10月22日16时15分19分
   
我只是索引车辆表中查询中使用的所有列或任何特定模式进行索引? -  mirza vu Oct 22 '16 at 15:21
   
有约25k辆车,1k经销商,60制造,1k型号。哪个不大 我认为使用雄辩的大型数据库造成瓶颈。更好地不依赖于他们提供的雄辩的关系功能?或者可以将其用于简单关系查询。 -  mirza vu Oct 22 '16 at 15:24
   
我至少会确保你的所有*_id列都被索引,(假设他们永远不会是负数)也添加unsigned -  罗斯·威尔逊10月22日16日15时24分
   
完成。有很大的改善。大概475ms了。 -  mirza vu Oct 22 '16 at 15:27
   
我可能会误会,但存在应该比使用连接更有效率。你已经尝试使用联接手动吗?如果是这样,表现有何增加? -  罗斯·威尔逊 10月22日16时15分29分
   
与db raw和has一起使用时加入经销商部分的问题。它说“未知柱距”。 -  mirza vu Oct 22 '16 at 15:32
   
$ query-> join('dealers','vehicles.dealer_id','=','dealers.id') - > select(DB :: raw(“dealers.id,(6371 * acos(cos(radians($纬度(纬度))* cos(弧度(纬度))* cos(弧度(经度) - 弧度($ lon))+ sin(弧度($ lat))* sin(弧度(纬度))))AS距离“ have('distance','<',$ conditions-> get('distance')); -