Laravel / MYSQL(Eloquent) - 查询大表

时间:2016-06-01 11:23:44

标签: php mysql laravel laravel-5 eloquent

我正在制作一个在线目录,这个目录包含商家,这就是当前表结构的设置方式:

1)“商业”

  • ID(PK)
  • 姓名
  • Phone_Number
  • 电子邮件

2)标签

  • id(PK)
  • 标签

3)Business_tags

  • id(PK)
  • business_id(FK)
  • tag_id(FK)

业务表内部有超过9k行,超过84,269行,(“Business_tags”)表中有超过29,000行(因为企业可以有多个标记)。

在商业模式中,有如下内容:

public function tags()
{
   return $this->belongsToMany('App\Tags');
}

问题是当我尝试进行搜索时,例如,假设有人想要搜索“中文”,那么它需要的时间比返回值的时间要长。例如,我正在使用:

$business = Business::where(function ($business) use ($request) {

    $business->whereHas('tags', function ($tag) use ($request) {

    }); 

})->paginate(20);

平均搜索:35秒显示结果。

这是原始的sql:

select * from `businesses` where (exists (select * from `tags` inner join `business_tags` on `tags`.`id` = `business_tags`.`tags_id` where `business_tags`.`business_id` = `businesses`.`id` and `name` in ('chinese')))

平均值:52.4秒在Sequel pro中运行(使用原始SQL语句)

任何想法如何提高此查询的性能以便更快?我希望拥有此功能,但用户不会等待这么长时间来回复!

编辑:

1   PRIMARY businesses  NULL    ALL NULL    NULL    NULL    NULL    8373    100.00  Using where
2   DEPENDENT SUBQUERY  business_tags   NULL    ALL NULL    NULL    NULL    NULL    30312   10.00   Using where
2   DEPENDENT SUBQUERY  tags    NULL    eq_ref  PRIMARY PRIMARY 4   halalhands.business_tags.tags_id    1   10.00   Using where

2 个答案:

答案 0 :(得分:1)

很多人也会告诉你。

  1. 您是否在查询中运行EXPLAIN
  2. 您是否在表中添加了索引? 因为即使有你提到的数据量,查询也应该比你报告的要快。
  3. 同时查看JOIN是否可以在这里工作,是否更快?(只是一个想法)

答案 1 :(得分:1)

你过度复杂了,没有正确使用雄辩的关系。你应该使用JOIN代替:

$businesses = Business::join('business_tags', 'business_tags.business_id', '=', 'business.id')
                        ->join('tags', function($join) {
                            $join->on('business_tags.tag_id', '=', 'tags.id')
                                 ->where('tags.name', '=', 'chinese');
                        })->get();

或者在原始SQL中:

SELECT *
FROM `business`
INNER JOIN `business_tags` ON `business_tags`.`business_id` = `business`.`id`
INNER JOIN `tags` ON `business_tags`.`tag_id` = `tags`.`id` AND `tags`.`name` = 'chinese'

(请注意,您可以将tags.name = 'chinese'部分放在WHERE子句中并产生相同的效果)

您当前的查询执行一个存在子查询,以获取数据透视表中符合条件的所有记录,然后将其传递回主查询。这是一个额外的步骤,这是不自然的。

雄辩的关系不适用于像这样的复杂查询,而是提供有关记录的其他相关信息,而无需手动编写其他查询。

例如,如果要查看业务,可以从其他表中查询with()电话号码和地址。您可能希望列出其标记,或sync()它们。但eloquent不构建和过滤查询,这就是查询构建器的用途。

如果您需要更多解释,请告诉我。