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
相关产品推荐
相关产品推荐

