我有一个搜索功能,它可以处理少量的数据,但是当我用一万个数据填充数据库时,当我试图搜索一些东西时,网站就会陷入加载状态。
pubblic function searchVideo(Request $request)
{
$searchTerm = $request->search;
$videos = Videos::with(['tags:id', 'stars:id'])
->where('title', 'LIKE', '%'.$searchTerm.'%')
->orWhereHas('tags', function ($query) use ($searchTerm) {
$query->where('name', 'LIKE', '%'.$searchTerm.'%');
})
->orWhereHas('stars', function ($query) use ($searchTerm) {
$query->where('name', 'LIKE', '%'.$searchTerm.'%');
})
->orderBy('created_at', 'desc')
->paginate(15);
return $videos;
}
如果我删除
->orWhereHas('tags', function ($query) use ($searchTerm) {
$query->where('name', 'LIKE', '%'.$searchTerm.'%');
})
->orWhereHas('
stars', function ($query) use ($searchTerm) {
$query->where('name', 'LIKE', '%'.$searchTerm.'%');
})
它工作得很好,但我不会得到我想搜索的每一个结果。
2条答案
按热度按时间z9zf31ra1#
不幸的是,这种查询搜索词
转换成SQL为
是一个臭名昭著的查询性能反模式。它不能随机访问任何普通的BTREE索引,而是必须扫描所有行以找到匹配的值。在小型测试数据库上速度快,在大型生产数据库上速度慢。
而且,您的查询中还有另一个臭名昭著的性能反模式:
这意味着RDBMS软件必须累积所有匹配的行,然后对它们进行排序,然后丢弃除少数行之外的所有行。
对此你能做些什么呢?这里有一些建议可能会有所帮助。
1.如果你在MySQL或MariaDB上,请确保你的
title
列被定义为VARCHAR(767)
或一些更小的字符数。不要将其定义为任何类型的TEXT
:对这些列的访问更慢。1.按如下所示创建复合索引
这将把要扫描的
title
列放在一个索引中。这可能比扫描整个表更快。而且,同一索引中的created_at
列可能会使ORDER BY ... LIMIT ...
操作更快。1.重新设计搜索操作,避免在
LIKE
子句中使用%
通配符。如果没有%
通配符,这些操作可能会利用索引。不过,我对您的应用程序了解不多,无法给予有关如何重新设计搜索的建议。1.切换到使用PostgreSQL并使用它的trigram索引。它们可以有效地处理
LIKE '%searchterm%'
查询。x4shl7ld2#
试试这个:public function searchVideo(Request $request){ $searchTerm = $request-〉search;$videos = Videos::with(['tags:id','stars:id'])-〉where('title','like','%'.$searchTerm.'%')-〉orWhereHas('tags',function($query)use($searchTerm){ $query-〉where('name ',' like','%'.$searchTerm.'%');})-〉orWhereHas('pornstars ',function($query)use($searchTerm){ $query-〉where('name','like','%'.$searchTerm.'%');})-〉orderBy('created_at','desc')-〉simplePaginate(15);
使用'like'而不是'LIKE'调用Laravel方法而不是SQL操作符。
使用simplePaginate方法代替paginate方法可以更有效。
你可以使用“select”来指定“videos”表中的特定列,而不是加载所有列。例如:
你也可以使用“orWhere”和Closure:与其使用多个orWhere方法,你可以将它们分组在一个闭包中,以避免冗余的查询构建。例如: