如何让php中的搜索查询更快?

xoshrz7s  于 2023-04-19  发布在  PHP
关注(0)|答案(2)|浏览(124)

我有一个搜索功能,它可以处理少量的数据,但是当我用一万个数据填充数据库时,当我试图搜索一些东西时,网站就会陷入加载状态。

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.'%');
            })

它工作得很好,但我不会得到我想搜索的每一个结果。

z9zf31ra

z9zf31ra1#

不幸的是,这种查询搜索词

->where('title', 'LIKE', '%'.$searchTerm.'%')

转换成SQL为

WHERE title LIKE '%searchTerm%'

是一个臭名昭著的查询性能反模式。它不能随机访问任何普通的BTREE索引,而是必须扫描所有行以找到匹配的值。在小型测试数据库上速度快,在大型生产数据库上速度慢。
而且,您的查询中还有另一个臭名昭著的性能反模式:

ORDER BY something DESC LIMIT some_small_number

这意味着RDBMS软件必须累积所有匹配的行,然后对它们进行排序,然后丢弃除少数行之外的所有行。
对此你能做些什么呢?这里有一些建议可能会有所帮助。
1.如果你在MySQL或MariaDB上,请确保你的title列被定义为VARCHAR(767)或一些更小的字符数。不要将其定义为任何类型的TEXT:对这些列的访问更慢。
1.按如下所示创建复合索引

CREATE INDEX title_created ON video(title, created_at DESC);

这将把要扫描的title列放在一个索引中。这可能比扫描整个表更快。而且,同一索引中的created_at列可能会使ORDER BY ... LIMIT ...操作更快。
1.重新设计搜索操作,避免在LIKE子句中使用%通配符。如果没有%通配符,这些操作可能会利用索引。不过,我对您的应用程序了解不多,无法给予有关如何重新设计搜索的建议。
1.切换到使用PostgreSQL并使用它的trigram索引。它们可以有效地处理LIKE '%searchterm%'查询。

x4shl7ld

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);

return $videos;
}

使用'like'而不是'LIKE'调用Laravel方法而不是SQL操作符。
使用simplePaginate方法代替paginate方法可以更有效。
你可以使用“select”来指定“videos”表中的特定列,而不是加载所有列。例如:

$videos = Videos::select('id', 'title', 'created_at')
        ->with(['tags:id', 'stars:id'])

你也可以使用“orWhere”和Closure:与其使用多个orWhere方法,你可以将它们分组在一个闭包中,以避免冗余的查询构建。例如:

->orWhere(function ($query) use ($searchTerm) {
         $query->where('name', 'like', '%'.$searchTerm.'%')
            ->orWhere('name', 'like', '%'.$searchTerm.'%');
    })

相关问题