Files
2026-09-08 15:25:23 +08:00
..
2026-09-08 15:25:23 +08:00
2026-09-08 15:25:23 +08:00

线上慢 SQL 索引优化分析(2026-08-26)

数据范围

  • 来源:/Users/dengzhangchen/Downloads/rm-1fyg92tzhbt23g9hw_slowlog_*.csv
  • 原始记录:638 条;按完整请求字段去重后 608 条;63 个 SQL Hash。
  • 数据库分布:pjcloudx_hardware 451 条、pjcloudx_wallet 153 条、pjcloudx_flow 4 条。
  • 主要扫描表:hard_order、hard_after_sale、wallet_transaction、act_hi_actinst。
  • 测试连接:OceanBase CE 4.3.5.5,MySQL 兼容模式;读取 SHOW CREATE TABLE、SHOW INDEX、EXPLAIN,并在测试库临时创建/回滚候选索引;未在生产库执行 DDL。

结论

强推荐,先上线

优先级 数据库/表 建议索引 主要覆盖日志 依据
P0 pjcloudx_hardware.hard_order (tenant_id, del_flag, create_time, user_id) 订单列表、分页 COUNT,Hash 270048891%7C1391、528608244%7C616 等 现有索引的第三列是 merchant_id 或 user_id,无法同时支撑租户+删除标记后的时间倒序;临时索引验证后由扫描+TOP-N 变为反向范围扫描。
P0 pjcloudx_hardware.hard_order (tenant_id, del_flag, order_no, order_type, order_status) 订单号精确 COUNT,Hash _1019382644%7C138 原执行计划只能在统计索引上按 order_status 扫描,再回表过滤订单号/类型;临时索引验证为三列等值范围扫描。
P0 pjcloudx_hardware.hard_order (tenant_id, del_flag, android_order_code) 设备订单号查询,Hash _986870313%7C628 原计划扫描约 98 万行后回表过滤 android_order_code;临时索引验证为等值范围扫描。
P0 pjcloudx_hardware.hard_after_sale (tenant_id, order_id, id) 订单列表中的“每单最新售后”子查询,覆盖 233 条相关记录 原表只有主键,GROUP BY order_id + MAX(id) 为全表扫描;临时索引验证后为有序范围扫描并使用 Merge Group By。
P0 pjcloudx_wallet.wallet_transaction (tenant_id, del_flag, create_time, user_id) 无业务类型条件的钱包流水首页,Hash 698590166%7C408 原计划全表扫描并排序;临时索引验证后为反向范围扫描,直接取前 10 行。
P0 pjcloudx_wallet.wallet_transaction (tenant_id, del_flag, biz_type(8), create_time, user_id) 钱包流水按业务类型筛选列表/COUNT,Hash 2036241023%7C466、255738862%7C620 等 biz_type 是 TINYTEXT,必须使用前缀索引;临时索引验证后可按租户、删除标记、业务类型及时间范围扫描。
P0 pjcloudx_flow.act_hi_actinst (ASSIGNEE_, END_TIME_) 流程历史待办查询,Hash _2096433074%7C126 原计划全表扫描并排序;临时索引验证后为反向范围扫描,直接满足 ORDER BY END_TIME_ DESC LIMIT 10。

条件推荐,先观察资源与收益

优先级 建议索引 适用场景 说明
P1 pjcloudx_hardware.hard_order (tenant_id, del_flag, order_status, pay_time, merchant_id) 按支付状态+支付时间汇总,Hash _1655261703%7C470 等 临时索引可将范围缩小到状态/时间,但仍需要回表和聚合;建议 P0 上线后按 EXPLAIN 和实际耗时决定。
P1 pjcloudx_hardware.hard_order (tenant_id, del_flag, merchant_dept_id, order_status, merchant_type, pay_time) 指定商户部门的支付统计,Hash 1634334540%7C358 等 对指定部门过滤收益明显;宽索引写放大较大,先对高频租户/接口评估。
P1 pjcloudx_wallet.wallet_manage (tenant_id, dept_id, id) 钱包按部门聚合 仅用于小维表定位钱包 ID;表规模较小时收益有限,适合与钱包统计接口一起验证。

暂不建议只靠加索引解决

  • 统计类 SQL 使用派生表、外层权限过滤和 ORDER BY CASE,索引只能减少底层扫描,不能消除派生表物化/聚合成本;建议后续改为先过滤再聚合,并移除 COUNT 查询中的无意义排序。
  • hard_order 订单详情列表反复 LEFT JOIN 最新售后子查询;P0 索引后仍建议将“最新售后 ID”改为窗口/预聚合或单独维护字段。
  • UPDATE hard_door_cabinet ... WHERE id = ? AND del_flag = ? AND tenant_id = ? 已命中主键 id,慢点更可能是锁等待、事务或网络;加索引不能解决,需结合 SHOW PROCESSLIST、锁等待和事务耗时排查。

上线步骤

  1. 低峰期逐条执行 01_add_indexes.sql,每条 DDL 单独观察完成时间和租户延迟。
  2. 执行前确认同名索引不存在;OceanBase 建索引可能持续几十秒到数分钟,不要重复提交。
  3. DDL 完成后对代表性 SQL 执行 EXPLAIN,确认使用新索引且不出现 TABLE FULL SCAN。
  4. 观察 15–30 分钟慢 SQL、CPU、IO、事务提交延迟;若写入延迟明显,再评估 P1 索引。
  5. 统计接口仍慢时,优先改写 SQL,再考虑继续增加宽复合索引。

验证记录

临时索引均已在测试库创建并回滚,最终检查无 tmp_% 索引残留。验证结果:

  • 订单时间分页:TABLE RANGE SCAN ... Reverse,不再全表扫描/大范围 TOP-N。
  • 钱包业务流水:TABLE RANGE SCAN ... Reverse,biz_type(8) 前缀索引可用。
  • 最新售后:MERGE GROUP BY + TABLE RANGE SCAN,不再全表扫描。
  • 流程历史:TABLE RANGE SCAN ... Reverse,不再全表扫描。