Laravel雄辩地查询到200万行需要很长时间

时间:2019-11-17 17:54:26

标签: laravel laravel-5 indexing eloquent mariadb

我必须从具有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查询,以便在表具有数百万行的情况下将查询响应减少到几秒钟?

2 个答案:

答案 0 :(得分:3)

您需要索引,索引是按某些列对数据进行细分的。您正在访问file_idcreated_at。因此,以下索引将有助于提高性能。

$table->index(['file_id', 'created_at']);

索引将增加插入时间,并使查询具有奇怪的执行计划。如果您在执行查询之后的查询之前对查询使用SQL EXPLAIN,我们可以验证它是否可以解决问题。

答案 1 :(得分:1)

这是为加快页面加载速度而进行的更新。

  1. 如此缓慢的查询的真正罪魁祸首不是上述特定查询。在上述查询获取数据之后,php遍历数据并在其中进行子查询以检查某些内容。该查询使用filename列在每次迭代期间搜索数据。由于filename是字符串且未建立索引,因此该控制器的响应时间花了很长时间,因为每个子查询都在foreach循环中爬行了150万行。删除此子查询后,加载时间减少了很多。

  2. 其次,我按照上面@mrhn和@ceejayoz的建议将索引添加到file_idcreated_at中。我创建了一个这样的迁移文件:

    Schema::table('images', function (Blueprint $table) {
        $table->index('file_id', 'created_at');
    });        
    
  3. 进一步优化了PHP脚本。我删除了所有使用fileNames进行搜索的查询,并将其更改为使用id来获取结果。这样做在整个应用程序中产生了巨大的变化,并且由于高峰时段的CPU工作量减少而提高了服务器速度。

  4. 最后,我通过执行以下步骤优化了服务器:

    • 完成所有的百胜更新
    • 更新了Litespeed
    • 调整了Apache配置文件,其中包括一些缓存模块并安装了EA-PHP 7.3
    • 更新后的cPanel
    • 调整了Mysql以允许您的服务器利用更多的服务器资源。

编辑完上述所有步骤后,发现加载速度有很大差异。结果如下:

之前: enter image description here

之后: enter image description here

感谢对此发表评论的每一个人。您的评论帮助我执行了上述所有步骤,结果取得了丰硕的成果。谢谢堆。