【问题标题】:Laravel Query Builder orderBy id DESC is very slow on 100k rowsLaravel Query Builder orderBy id DESC 在 100k 行上非常慢
【发布时间】:2021-12-20 05:27:35
【问题描述】:

我有一个包含 100k 产品的数据库,这是我的查询

 $products = DB::table('product')
    ->leftJoin('product_description', 'product_description.product_id', 'product.product_id')
    ->leftJoin('product_to_category','product_to_category.product_id','product.product_id')
    ->select(self::$select_fields)
    ->where('product_description.language', $language)
    ->groupBy('product.product_id');

    if (!empty($filter->keyword)) {
      $products->where('product_description.title','LIKE','%'. $filter->keyword .'%');
    }

    if (!empty($filter->category_id)) {
      $products->where('product_to_category.category_id','=',$filter->category_id);
    }
    
    if (!empty($filter->range)) {
      $range= explode(',',$filter->range);
      $products->whereBetween('product.price', [$range[0], (!empty($range[1]))? $range[1] : $range[0]]);
    }
    
    return $products->orderBy('product.product_id','DESC')->where('product.status',1)->limit(50);

此查询在 12.6 秒内加载。如果我删除->orderBy('product.product_id','DESC'),查询将在 0.800 毫秒内运行。

在我的数据库中,我在 product_description.product_id 上有索引键,product_to_category.product_idproduct.id 设置为主要

我已经看到 orderBY desc 在大型数据库中减慢了很多,是否有解决方法,我需要通过 DESC 订购它,因为我想要上传“最新”,我尝试将其设置在“created_at”列但大体相同

编辑

我在没有 Laravel 的情况下试过,基本上速度差不多,按 DESC 排序会减慢查询速度,有没有一般的解决方案或者基本上 DESC 很慢,应该避免使用 BIG 数据库?

【问题讨论】:

  • 你有没有尝试先接受你的查询,然后在 make orderBy 之后有什么改变吗?
  • @HasanÇetin 进行查询后,我只得到 50 个结果,因此使用集合进行排序对我来说不起作用
  • 您是否尝试手动执行 mysql 查询以查看结果?我认为你应该在你的表中添加索引。这根本与 laravel 无关。
  • @EmilGeorgiev 是的,我做的速度差不多,通过 DESC 订购会减慢很多,无论有没有 eloquent
  • 您使用的是什么 RDBMS 供应商和版本(假设 MySQL)?表的架构是什么?例如:SHOW CREATE TABLE products 的结果。 EXPLAIN 的查询结果是什么?最后,您的数据库的配置设置是什么?

标签: php sql laravel eloquent


【解决方案1】:

您按product.product_id 分组,我猜测选择仅包含产品表中的列。在这种情况下,左连接可以被移除——或者——被一个存在查询替换。 group by 可以完全删除。连接将行相乘并按压缩它们;删除后,查询变得更简单,希望更快:

select foo, bar, baz
from product
where status = ?
and price between ? and ? -- add this where clause if you need to filter on product price
and exists ( -- add this subquery if you need to filter on description language and/or title
    select 1
    from product_description
    where product_description.product_id = product.product_id
    and product_description.language = ?
    and product_description.title like ?
)
and exists ( -- add this subquery if you need to filter on category id
    select 1
    from product_to_category
    where product_to_category.product_id = product.product_id
    and product_to_category.category_id = ?
)
order by product_id desc
limit 50

【讨论】:

  • 我总是从所有 3 个表中获取数据
  • 那么您的分组依据是错误的 (stackoverflow.com/q/34115174)。您可以从其他表中获取随机行。更快地得到错误结果是没有意义的。
【解决方案2】:

我认为您可以定义DESC 索引,因为列上的默认索引是ASC

例如:

CREATE INDEX product_index ON product (product_id DESC);

more information

【讨论】:

  • 请注意,它似乎只适用于 MySQL 8 或更高版本。在旧版本中,直接忽略 DESC 关键字。
  • 一个普通的索引可以向后使用,所以这个“解决方案”不应该改变任何东西。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-27
  • 2019-03-29
  • 2013-07-31
  • 2015-03-13
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多