我必须从具有200万行的表中提取数据。雄辩的查询看起来像这样:
$imagesData = Images::whereIn('file_id', $fileIds)
->with('image.user')
->with('file')
->orderBy('created_at', 'DESC')
->simplePaginate(12);
$fileIds
中使用的whereIn
数组可以包含100甚至1000个文件ID。
上面的查询在小表中工作正常。但是在Images
表中有超过200万行的生产站点中,需要15秒以上才能得到答复。我仅将Laravel用于api。
我已经阅读了有关该主题的其他讨论。我将paginate()
更改为simplePaginate()
。一些人建议,也许对DB::
进行whereRaw
查询可能比whereIn
更好。有人说这可能是由于在处理whereIn
时php中的PDO引起的,还有一些人建议使用我已经使用的Images::whereIn
。
我将MariaDB与用于数据库引擎的InnoDB一起使用,并将其加载到RAM中。 sql查询在所有其他查询中的性能都很好,但是只有那些必须从大型表中收集数据的查询才需要时间。
如何优化上面的laravel查询,以便在表具有数百万行的情况下将查询响应减少到几秒钟?
答案 0 :(得分:3)
您需要索引,索引是按某些列对数据进行细分的。您正在访问file_id
和created_at
。因此,以下索引将有助于提高性能。
$table->index(['file_id', 'created_at']);
索引将增加插入时间,并使查询具有奇怪的执行计划。如果您在执行查询之后的查询之前对查询使用SQL EXPLAIN
,我们可以验证它是否可以解决问题。
答案 1 :(得分:1)
这是为加快页面加载速度而进行的更新。
如此缓慢的查询的真正罪魁祸首不是上述特定查询。在上述查询获取数据之后,php遍历数据并在其中进行子查询以检查某些内容。该查询使用filename
列在每次迭代期间搜索数据。由于filename
是字符串且未建立索引,因此该控制器的响应时间花了很长时间,因为每个子查询都在foreach
循环中爬行了150万行。删除此子查询后,加载时间减少了很多。
其次,我按照上面@mrhn和@ceejayoz的建议将索引添加到file_id
和created_at
中。我创建了一个这样的迁移文件:
Schema::table('images', function (Blueprint $table) {
$table->index('file_id', 'created_at');
});
进一步优化了PHP脚本。我删除了所有使用fileNames
进行搜索的查询,并将其更改为使用id
来获取结果。这样做在整个应用程序中产生了巨大的变化,并且由于高峰时段的CPU工作量减少而提高了服务器速度。
最后,我通过执行以下步骤优化了服务器:
编辑完上述所有步骤后,发现加载速度有很大差异。结果如下:
感谢对此发表评论的每一个人。您的评论帮助我执行了上述所有步骤,结果取得了丰硕的成果。谢谢堆。