You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Query Builder按product_id倒序查10万行商品过慢如何优化?

问题根因

慢的核心不是DESC排序本身的问题,是你的查询没有命中能覆盖排序逻辑的索引:

  • 不加排序时,数据库只需匹配到前50条符合过滤+关联条件的记录就可以直接返回,耗时极短
  • 加了DESC排序后,数据库需要先把所有符合条件的记录全部查出来,执行全量排序后才能取前50条,10万级数据加多表关联的排序操作自然耗时飙升

通用解决方案

1. 调整索引结构,让排序直接走索引

给product表建联合索引,把前置过滤字段和排序字段组合到一起,让数据库可以直接按索引的倒序顺序扫描,匹配到50条符合条件的记录就终止查询,完全避免全量排序:

-- 按product_id倒序的场景
CREATE INDEX idx_status_pid_desc ON product (status, product_id DESC);
-- 如果后续切为created_at倒序,建下面的索引
CREATE INDEX idx_status_createtime_desc ON product (status, created_at DESC);

同时优化关联表的索引,避免关联时回表查询:

  • product_description表建联合索引:(product_id, language, title),覆盖关联+语言过滤+关键词查询的需求
  • product_to_category表建联合索引:(product_id, category_id),覆盖关联+分类过滤的需求

2. 改写查询逻辑,缩小排序数据集

不要先做多表关联再排序,先从主表product里把符合基础条件的前50条最新记录的ID查出来,再用这50个ID去关联其他表做过滤,关联操作的数据集直接从10万级降到50条,速度会有数量级提升,Laravel写法参考:

// 第一步:仅查询主表,走覆盖索引快速拿到50个最新的符合基础条件的商品ID
$productIds = DB::table('product')
    ->where('status', 1)
    ->when(!empty($filter->range), function ($query) use ($filter) {
        $range = explode(',', $filter->range);
        $query->whereBetween('price', [
            $range[0],
            !empty($range[1]) ? $range[1] : $range[0]
        ]);
    })
    ->orderBy('product_id', 'DESC')
    ->limit(50)
    ->pluck('product_id');

// 第二步:用少量ID关联其他表做剩余过滤,数据量极小
$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)
    ->whereIn('product.product_id', $productIds)
    ->where('product_description.language', $language)
    ->when(!empty($filter->keyword), function ($query) use ($filter) {
        $query->where('product_description.title', 'LIKE', '%' . $filter->keyword . '%');
    })
    ->when(!empty($filter->category_id), function ($query) use ($filter) {
        $query->where('product_to_category.category_id', '=', $filter->category_id);
    })
    ->groupBy('product.product_id')
    ->orderBy('product.product_id', 'DESC')
    ->get();

3. 误区澄清

大数据场景完全不需要避免DESC排序,只要排序逻辑有对应的索引支撑,正序和倒序的性能几乎没有差异。所有排序慢的问题本质都是排序操作没有走索引,需要对全量命中数据做手动排序(也就是数据库常说的filesort操作)导致的。


内容的提问来源于stack exchange,提问作者Frosty

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 05:45:01