Laravel Eloquent 查询 200 万行需要很长时间

Nee*_*eel 6 indexing mariadb laravel eloquent laravel-5

我必须从一个有 200 万行的表中提取数据。雄辩的查询如下所示:

$imagesData = Images::whereIn('file_id', $fileIds)
                    ->with('image.user')
                    ->with('file')
                    ->orderBy('created_at', 'DESC')
                    ->simplePaginate(12);
Run Code Online (Sandbox Code Playgroud)

中使用的$fileIds数组whereIn可以包含 100 甚至 1000 个文件 ID。

上述查询在小表中工作正常。但是在Images表中有超过 200 万行的生产站点中,需要超过 15 秒才能得到回复。我仅将 Laravel 用于 api。

我已阅读有关此主题的其他讨论。我换paginate()simplePaginate()。一些人建议也许有一个DB::查询whereRaw可能比whereIn. 有人说这可能是由于处理时 php 中的 PDO 而whereIn有些人建议使用Images::whereIn我已经使用过的。

我使用 MariaDB,将 InnoDB 用于数据库引擎并将其加载到 RAM 中。sql 查询对于所有其他查询都表现良好,但只有那些必须从像这样的大表中收集数据的查询才需要时间。

我如何优化上面的 Laravel 查询,以便在表有数百万行时,如果可能的话,我可以将查询响应减少到几秒钟?

mrh*_*rhn 6

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

$table->index(['file_id', 'created_at']);
Run Code Online (Sandbox Code Playgroud)

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


Nee*_*eel 5

以下是为加快页面加载而采取的步骤的更新。

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

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

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

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

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

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

前: 在此输入图像描述

后: 在此输入图像描述

感谢所有对此发表评论的人。您的评论帮助我执行了上述所有步骤,结果是富有成效的。谢谢大家。