LOGO 首页 OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 技术文档 其他文档  
 
网站管理员

千万级订单表慢查询,我是怎么把 38 秒压到毫秒级的

admin
2026年8月24日 14:43 本文热度 41

一条后台订单列表,点开要等半天。

表面上看像是前端慢,或者 MySQL 卡了。实际跑了一圈 EXPLAIN ANALYZE 才发现,真正拖慢链路的不是单一索引,而是四表联查里主表没筛住、关联表跟着陪跑。

这篇不讲索引课,讲一次真实的工程化优化:索引和 SQL 一起改。

一、先把问题说清楚:为什么这条 SQL 会慢

原始查询是一个很典型的订单列表页:

SELECT
  o.id,
  o.order_no,
  o.status,
  o.amount,
  o.create_time,
  u.nickname,
  u.phone,
  m.merchant_name,
  p.pay_status,
  l.delivery_status
FROM orders o
JOIN users u ON u.id = o.user_id
JOIN merchants m ON m.id = o.merchant_id
LEFT JOIN order_payments p ON p.order_id = o.id
LEFT JOIN order_logistics l ON l.order_id = o.id
WHERE o.merchant_id 10086
  AND o.status IN (123)
  AND o.create_time >= '2026-01-01'
  AND u.region_id IN (135)
  AND m.status 1
ORDER BY o.create_time DESC
LIMIT 20;

这个场景很真实:

  • 主表是订单
  • 还要关联用户、商家、支付、物流
  • 有状态过滤
  • 有时间过滤
  • 还要排序和分页

如果主表没吃到索引,后面的 join 再漂亮也救不回来。

二、先看执行计划:瓶颈其实很直接

优化前的 EXPLAIN ANALYZE 里,最重的一句是:

Table scan on o
rows = 1e+6
actual time = 21794ms

也就是说,orders 先扫了 100 万行。

后面还有排序:

Sort: o.create_time DESC

支付表和物流表也各自扫了 30 万行左右。

整条链路跑下来,大概到了 38 秒级别。

这时候不要先动一堆表,先盯最重的那一环:orders

三、主表先吃索引,关联表只补关键索引

我先给主表加联合索引:

CREATE INDEX idx_orders_merchant_status_ct_user
ON orders(merchant_id, status, create_time, user_id);

这个顺序不是拍脑袋:

  • merchant_id 是等值条件
  • status 也是等值条件
  • create_time 负责范围筛选和排序
  • user_id 方便后续 join 用户表

一句话:等值字段放前面,范围字段放后面。

关联表只补真正会被用到的键,不乱建:

CREATE INDEX idx_users_region_id_id ON users(region_id, id);
CREATE INDEX idx_order_payments_order_id ON order_payments(order_id);
CREATE INDEX idx_order_logistics_order_id ON order_logistics(order_id);

如果 merchants 也经常按状态筛选,再补:

CREATE INDEX idx_merchants_status_id ON merchants(status, id);

这里要记住一件事:索引不是越多越快。 它会增加写入成本,也会增加维护成本。

四、索引之外,还要改 SQL

这次优化里,第二件事更关键:不是只加索引,而是把 SQL 改得更省。

很多慢查询的问题,不是“找得慢”,而是“找得太多”。

所以我把主查询改成先截断,再 join:

SELECT
  o.id,
  o.order_no,
  o.status,
  o.amount,
  o.create_time,
  u.nickname,
  u.phone,
  m.merchant_name,
  p.pay_status,
  l.delivery_status
FROM (
  SELECT id, user_id, merchant_id, status, amount, create_time
  FROM orders
  WHERE merchant_id 10086
    AND status IN (123)
    AND create_time >= '2026-01-01'
  ORDER BY create_time DESC
  LIMIT 20
) o
JOIN users u ON u.id = o.user_id
JOIN merchants m ON m.id = o.merchant_id
LEFT JOIN order_payments p ON p.order_id = o.id
LEFT JOIN order_logistics l ON l.order_id = o.id
WHERE u.region_id IN (135)
  AND m.status 1
ORDER BY o.create_time DESC;

这个思路很重要:

先缩小主表结果集,再去连其他表

而不是把四张表先搅成一锅,再让数据库慢慢筛。

五、优化后的结果:两类场景都验证了

1. 列表联查

优化后,orders 已经走索引了:

Index range scan on o using idx_orders_merchant_status_ct_user

主表不再全表扫,耗时直接降到毫秒级。

不过这里有个细节要实话实说:

最终返回 rows = 0

原因是 u.region_id IN (1, 3, 5) 把前面筛出来的候选行又过滤掉了。

这不影响优化结论,只是说明这组测试条件下没有命中最终结果。

2. 订单详情

我又测了一个非常典型的详情查询:

SELECT
  o.id, o.order_no, o.status, o.amount, o.create_time,
  u.nickname, u.phone
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE o.order_no 'O000000000000001';

优化前:

Table scan on o
actual time = 21728ms

优化后,补了唯一索引:

CREATE UNIQUE INDEX idx_orders_order_no ON orders(order_no);

再跑一次:

Rows fetched before execution
actual time = 0.0127..0.019

这个对比非常适合写进文章里,因为它说明:

唯一业务键,必须单独处理

六、分页也不能只靠索引硬扛

我还测了一个深分页场景:

SELECT
  o.id, o.order_no, o.status, o.create_time
FROM orders o
WHERE o.merchant_id 10086
  AND o.status IN (123)
ORDER BY o.create_time DESC
LIMIT 10000020;

这种写法很多后台都在用,但它的问题是:

越往后翻,越慢

更好的方式是游标分页:

SELECT
  o.id, o.order_no, o.status, o.create_time
FROM orders o
WHERE o.merchant_id 10086
  AND o.status IN (123)
  AND o.create_time '上一页最后一条时间'
ORDER BY o.create_time DESC
LIMIT 20;

这不是加索引,而是改查询方式。

七、这次实战的决策表

问题
先动什么
原因
主表全表扫
先加主表联合索引
主表不缩小,后面 join 没意义
详情页按业务键查
单独加唯一索引
业务键要做到一跳命中
列表页太慢
索引 + 先 limit 再 join
先减少数据量,再补详情
深分页慢
改游标分页
offset 越大越慢
每个字段都想加索引
先停一下
索引越多,写入和维护成本越高

八、最后的结论

这次优化最有价值的地方,不是“加了几个索引”,而是确认了一条完整路径:

索引负责缩小范围,SQL 负责控制过程

真正的优化,从来不是单点动作,而是索引和 SQL 一起改。

如果你下次也遇到四表联查慢,先别急着加一堆索引。先看主表有没有被筛住,再看 join 是否真的必要,最后再看分页方式有没有拖后腿。


阅读原文:点击这里


该文章在 2026/8/24 14:43:16 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-1  粤公网安备44030602007207号