抱歉很久没写技术博客。
自从LLM爆发之后,写概念堆叠的所谓“博客”已经没有意义了,那么我会思考我的博客还有什么作用。
得出的结论是:具体业务的讨论仍然是有价值的
所以之后会随缘更新一些强业务相关的博客
为什么说随缘呢?因为这段时间经历了一些事情,让我感觉比起死磕技术(工作),体验生活才是我的首要目标
别说什么裁员的,真裁员我还来不及高兴呢
以上,2025.06.12
背景:维护中遇到一段“屎山 SQL”
近期在优化一个业务接口性能时,发现其背后依赖了一段极为复杂的 SQL 查询,执行时间长达 20 多秒。这段 SQL 看似在统计一些业务数据,但结构混乱、嵌套严重、含义难懂,最严重的是,其中一段使用了过度复杂的窗口函数嵌套,成为性能瓶颈。
本文记录我分析、重构并优化该 SQL 的过程,并结合实际经验,聊聊 SQL 优化中“理解数据关系 vs 语法技巧”的重要性。
原始 SQL 功能分析
该 SQL 由三部分构成,通过 UNION ALL 拼接。表结构如下:
- sdd_t_ace: 主表,记录交易信息。字段有 scan_seq_no, tr_date, status, b_code 等。
- aaa_t_tr_over_log: 记录交易“处理完成”的日志。字段有 scan_seq_no, finished_time
- aaa_t_tr_obtain_log: 记录交易“领取处理”的日志。字段有 ace_id, tr_date
SQL 三段查询的业务目标(推测)
太难看了只能靠猜
序号SQL 功能推测业务目标①查询今日内所有交易记录数量统计交易总量②查询今日内未完成的交易记录统计待处理数量③查询今日内已完成但处理时间晚于某时间点,且已被领取的任务检查延迟处理的任务第三段 SQL(屎山核心)原样示例(已简化)
[code]select scan_seq_no, finished_time, obtain_timefrom ( select scan_seq_no, finished_time from ( select t1.scan_seq_no, t2.finished_time, row_number() over(partition by t2.scan_seq_no order by t2.finished_time desc) as rank1 from sdd_t_ace t1 left join aaa_t_tr_over_log t2 on t1.scan_seq_no = t2.scan_seq_no where t1.status != 0 and t1.tr_date between curdate() and '2025-06-06 16:30' ) k1 where finished_time >= '2025-06-06 16:30' and rank1 = 1) m1left join aaa_t_tr_obtain_log m2 on m1.scan_seq_no = m2.scan_seq_nowhere m2.tr_date = '2025-06-06 16:30' and sdd.tr_date between curdate() and '2025-06-06 16:30' and m2.tr_date |