如何使用whereHas优化此查询?

时间:2016-04-03 07:59:49

标签: php mysql laravel laravel-5 query-optimization

我正在使用此查询过滤出包含城市和类别的商店。当我在stores表中有大约1000条记录时,它工作正常。现在,当我有5000条记录时,生成结果大约需要3-10秒。

在我的案例中,商店属于多个类别。

如何使用Eloquent orm或DB::raw()优化此查询?

$stores = Store::where('city_id', $city_id)
        ->where('disabled', '0')
        ->whereHas('categories', function($q) use ($category_id){
            $q->where('category_id', '=', $category_id);
        })
        ->orderBy('rating','DESC')->paginate(10);

2 个答案:

答案 0 :(得分:5)

我使用whereRaw解决了我的问题DB::raw()DB::select()无法paginate()收集。

问题:

执行时间:11.449304103851s

city_id = 6& $category_id = 1

$stores = Store::where('city_id', $city_id)
        ->where('disabled', '0')
        ->whereHas('categories', function($q) use ($category_id){
            $q->where('category_id', '=', $category_id);
        })
        ->orderBy('rating','DESC')->paginate(10);

解决方案:

执行时间:0.033660888671875s

city_id = 6& $category_id = 1

$stores = Store::
    where('city_id', $city_id)
    ->where('disabled', '0')
    ->whereRaw('stores.id in (select store_id from store_categories_pivot where category_id = ?)', [$category_id])
    ->orderBy('rating','DESC')
    ->paginate(10);

答案 1 :(得分:1)

您可以尝试运行:

$stores = Store::where('city_id', $city_id)
        ->where('disabled', '0')
        ->leftJoin('categories','categories.store_id','=', 'stores.id')
        ->where('category_id', $category_id)
        ->orderBy('rating','DESC')->paginate(10);

现在验证您的执行时间。但是您可能需要为此类查询添加额外的更改,因为我们不知道确切的表结构以及数据的组织方式。

如果没有帮助,您应该获取执行的查询(确切查询),然后运行

EXPLAIN your_query
数据库工具中的

向您展示究竟发生了什么,以及您是否真的拥有所需的所有内容的索引。

查看您的查询,您应该为列stores编制索引:

  • city_id
  • 禁用
  • 等级

categories你应该有列的索引:

  • CATEGORY_ID
  • STORE_ID

或这些列的某些组合。