Files
pj_service_cloud/db/slowlog_optimization_20260826/README.md
T
2026-09-08 15:25:23 +08:00

55 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 线上慢 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`,不再全表扫描。