来OB这么久还没有接触啥金融的SQL,只能发点其他行业的数据库SQL优化案例。

今天拿到手的这个案例SQL 传统行业的,很奇葩的SQL,表设计三范式都没弄好。

什么医疗,交通,能源这些传统行业的业务设计,SQL语句最奇葩了,也挺好玩的,有挑战性。

慢SQL:

SELECT  LI.STATUS, FI.SOFL_SEQ_NR ,PI.CLAZZ,PI.HV_TYPE
FROM LNF LI, PNF PI, FNF FI
WHERE 1=1
AND LI.ALN_CD = DECODE(FI.ALN_CD, 'OQ', 'CZ', FI.ALN_CD)
and li.dep_arp_cd = fi.act_dep_cd
and li.flt_nr = DECODE(fi.aln_cd,'OQ',substr(( select cz_flt_nr from OQ_FLT_INFO oq where substr(oq.oq_flt_nr,3,4)= fi.flt_nr) ,3,4), fi.flt_nr)
and li.FLT_DT=FI.FLT_DT
AND LI.FK_PSGR_ID = PI.PSGR_ID
AND (PI.HV_TYPE IS NOT NULL OR PI.CLAZZ IN ('F', 'F1', 'J', 'C', 'D', 'I', 'O'))
and FI.FLT_DT=date'2024-04-01'
and FI.SCH_DEP_CD='CAN'
ORDER BY FI.SOFL_SEQ_NR ;

执行时间:

执行计划(看不看得懂随缘、反正我没看):

1   #NSET2: [2903, 556029, 632]
2 #PIPE2: [2903, 556029, 632]
3 #PIPE2: [2901, 556029, 632]
4 #PRJT2: [2899, 556029, 632]; exp_num(4), is_atom(FALSE)
5 #SORT3: [2899, 556029, 632]; key_num(1), is_distinct(FALSE), top_flag(0), is_adaptive(0)
6 #UNION FOR OR2: [2788, 556029, 632]; key_num(0), outer_join(-)
7 #SLCT2: [1334, 278014, 632]; LI.FLT_NR = exp_simple_case
8 #HASH2 INNER JOIN: [1334, 278014, 632]; KEY_NUM(2); KEY(FI.ACT_DEP_CD=LI.DEP_ARP_CD AND exp_simple_case=LI.ALN_CD) KEY_NULL_EQU(0, 0)
9 #BLKUP2: [1, 385, 247]; IDX_FLIGHT_INFO02(FI)
10 #SSEK2: [1, 385, 247]; scan_type(ASC), IDX_FLIGHT_INFO02(FNF as FI), scan_range[(exp_cast(2024-04-01),'CAN',min),(exp_cast(2024-04-01),'CAN',max))
11 #SLCT2: [1324, 37479, 385]; NOT(PI.HV_TYPE IS NULL)
12 #HASH2 INNER JOIN: [1324, 37479, 385]; RKEY_UNIQUE KEY_NUM(1); KEY(LI.FK_PSGR_ID=PI.PSGR_ID) KEY_NULL_EQU(0)
13 #SLCT2: [1324, 37479, 385]; NOT(PI.HV_TYPE IS NULL)
14 #NEST LOOP INDEX JOIN2: [1324, 37479, 385]
15 #ACTRL: [1324, 37479, 385];
16 #BLKUP2: [1049, 37479, 247]; INDEX_LU_INTO_TAG_0416(LI)
17 #SLCT2: [1049, 37479, 247]; LI.FLT_DT = var3
18 #SSCN: [1049, 37479, 247]; INDEX_LU_INTO_TAG_0416(LNF as LI); btr_scan(1)
19 #BLKUP2: [244, 1, 30]; INDEX33555482(PI)
20 #SSEK2: [244, 1, 30]; scan_type(ASC), INDEX33555482(PNF as PI), scan_range[LI.FK_PSGR_ID,LI.FK_PSGR_ID]
21 #CSCN2: [475, 3573399, 138]; INDEX33555481(PNF as PI); btr_scan(1)
22 #SLCT2: [1334, 278014, 632]; LI.FLT_NR = exp_simple_case
23 #HASH2 INNER JOIN: [1334, 278014, 632]; KEY_NUM(2); KEY(FI.ACT_DEP_CD=LI.DEP_ARP_CD AND exp_simple_case=LI.ALN_CD) KEY_NULL_EQU(0, 0)
24 #BLKUP2: [1, 385, 247]; IDX_FLIGHT_INFO02(FI)
25 #SSEK2: [1, 385, 247]; scan_type(ASC), IDX_FLIGHT_INFO02(FNF as FI), scan_range[(exp_cast(2024-04-01),'CAN',min),(exp_cast(2024-04-01),'CAN',max))
26 #SLCT2: [1324, 37479, 385]; (exp11 AND PI.CLAZZ IN LIST)
27 #HASH2 INNER JOIN: [1324, 37479, 385]; RKEY_UNIQUE KEY_NUM(1); KEY(LI.FK_PSGR_ID=PI.PSGR_ID) KEY_NULL_EQU(0)
28 #SLCT2: [1324, 37479, 385]; (exp11 AND PI.CLAZZ IN LIST)
29 #NEST LOOP INDEX JOIN2: [1324, 37479, 385]
30 #ACTRL: [1324, 37479, 385];
31 #BLKUP2: [1049, 37479, 247]; INDEX_LU_INTO_TAG_0416(LI)
32 #SLCT2: [1049, 37479, 247]; LI.FLT_DT = var4
33 #SSCN: [1049, 37479, 247]; INDEX_LU_INTO_TAG_0416(LNF as LI); btr_scan(1)
34 #BLKUP2: [244, 1, 30]; INDEX33555482(PI)
35 #SSEK2: [244, 1, 30]; scan_type(ASC), INDEX33555482(PNF as PI), scan_range[LI.FK_PSGR_ID,LI.FK_PSGR_ID]
36 #CSCN2: [475, 3573399, 138]; INDEX33555481(PNF as PI); btr_scan(1)
37 #SPL2: [1, 279, 343]; key_num(2), spool_num(1), is_atom(FALSE), has_var(0), sites(-)
38 #PRJT2: [1, 279, 343]; exp_num(2), is_atom(FALSE)
39 #HASH2 INNER JOIN: [1, 279, 343]; KEY_NUM(1); KEY(exp11=FI.FLT_NR) KEY_NULL_EQU(0)
40 #CSCN2: [1, 279, 96]; INDEX33555478(OQ_FLT_INFO as OQ); btr_scan(1)
41 #BLKUP2: [1, 385, 247]; IDX_FLIGHT_INFO02(FI)
42 #SSEK2: [1, 385, 247]; scan_type(ASC), IDX_FLIGHT_INFO02(FNF as FI), scan_range[(exp_cast(2024-04-01),'CAN',min),(exp_cast(2024-04-01),'CAN',max))
43 #SPL2: [1, 279, 343]; key_num(2), spool_num(0), is_atom(FALSE), has_var(0), sites(-)
44 #PRJT2: [1, 279, 343]; exp_num(2), is_atom(FALSE)
45 #HASH2 INNER JOIN: [1, 279, 343]; KEY_NUM(1); KEY(exp11=FI.FLT_NR) KEY_NULL_EQU(0)
46 #CSCN2: [1, 279, 96]; INDEX33555478(OQ_FLT_INFO as OQ); btr_scan(1)
47 #BLKUP2: [1, 385, 247]; IDX_FLIGHT_INFO02(FI)
48 #SSEK2: [1, 385, 247]; scan_type(ASC), IDX_FLIGHT_INFO02(FNF as FI), scan_range[(exp_cast(2024-04-01),'CAN',min),(exp_cast(2024-04-01),'CAN',max))

表数据量:

上面SQL跑28秒,返回8行数据,还是挺慢的。

DM哥们说他已经加个HINT对 or 进行整体优化,但是还要跑12秒,客户不接受,所以找到我来看看。

加HINT优化方案:

SELECT /*+ OPTIMIZER_OR_NBEXP(2)  */ LI.STATUS, FI.SOFL_SEQ_NR ,PI.CLAZZ,PI.HV_TYPE
FROM LNF LI, PNF PI, FNF FI
WHERE 1=1
AND LI.ALN_CD = DECODE(FI.ALN_CD, 'OQ', 'CZ', FI.ALN_CD)
and li.dep_arp_cd = fi.act_dep_cd
and li.flt_nr = DECODE(fi.aln_cd,'OQ',substr(( select cz_flt_nr from OQ_FLT_INFO oq where substr(oq.oq_flt_nr,3,4)= fi.flt_nr) ,3,4), fi.flt_nr)
and li.FLT_DT=FI.FLT_DT
AND LI.FK_PSGR_ID = PI.PSGR_ID
AND (PI.HV_TYPE IS NOT NULL OR PI.CLAZZ IN ('F', 'F1', 'J', 'C', 'D', 'I', 'O'))
and FI.FLT_DT=date'2024-04-01'
and FI.SCH_DEP_CD='CAN'
ORDER BY FI.SOFL_SEQ_NR ;

 加HINT后执行计划:

1   #NSET2: [1372, 278014, 608]
2 #PIPE2: [1372, 278014, 608]
3 #PRJT2: [1371, 278014, 608]; exp_num(4), is_atom(FALSE)
4 #SORT3: [1371, 278014, 608]; key_num(1), is_distinct(FALSE), top_flag(0), is_adaptive(0)
5 #SLCT2: [1317, 278014, 608]; LI.FLT_NR = exp_simple_case
6 #HASH2 INNER JOIN: [1317, 278014, 608]; KEY_NUM(2); KEY(FI.ACT_DEP_CD=LI.DEP_ARP_CD AND exp_simple_case=LI.ALN_CD) KEY_NULL_EQU(0, 0)
7 #BLKUP2: [1, 385, 247]; IDX_FLIGHT_INFO02(FI)
8 #SSEK2: [1, 385, 247]; scan_type(ASC), IDX_FLIGHT_INFO02(FNF as FI), scan_range[(exp_cast(2024-04-01),'CAN',min),(exp_cast(2024-04-01),'CAN',max))
9 #SLCT2: [1307, 37479, 361]; (NOT(PI.HV_TYPE IS NULL) OR PI.CLAZZ IN LIST)
10 #HASH2 INNER JOIN: [1307, 37479, 361]; RKEY_UNIQUE KEY_NUM(1); KEY(LI.FK_PSGR_ID=PI.PSGR_ID) KEY_NULL_EQU(0)
11 #SLCT2: [1307, 37479, 361]; (NOT(PI.HV_TYPE IS NULL) OR PI.CLAZZ IN LIST)
12 #NEST LOOP INDEX JOIN2: [1307, 37479, 361]
13 #ACTRL: [1307, 37479, 361];
14 #BLKUP2: [1032, 37479, 235]; INDEX_LU_INTO_TAG_0416(LI)
15 #SLCT2: [1032, 37479, 235]; LI.FLT_DT = var2
16 #SSCN: [1032, 37479, 235]; INDEX_LU_INTO_TAG_0416(LNF as LI); btr_scan(1)
17 #BLKUP2: [244, 1, 30]; INDEX33555482(PI)
18 #SSEK2: [244, 1, 30]; scan_type(ASC), INDEX33555482(PNF as PI), scan_range[LI.FK_PSGR_ID,LI.FK_PSGR_ID]
19 #CSCN2: [467, 3573399, 126]; INDEX33555481(PNF as PI); btr_scan(1)
20 #SPL2: [1, 279, 343]; key_num(2), spool_num(0), is_atom(FALSE), has_var(0), sites(-)
21 #PRJT2: [1, 279, 343]; exp_num(2), is_atom(FALSE)
22 #HASH2 INNER JOIN: [1, 279, 343]; KEY_NUM(1); KEY(exp11=FI.FLT_NR) KEY_NULL_EQU(0)
23 #CSCN2: [1, 279, 96]; INDEX33555478(OQ_FLT_INFO as OQ); btr_scan(1)
24 #BLKUP2: [1, 385, 247]; IDX_FLIGHT_INFO02(FI)
25 #SSEK2: [1, 385, 247]; scan_type(ASC), IDX_FLIGHT_INFO02(FNF as FI), scan_range[(exp_cast(2024-04-01),'CAN',min),(exp_cast(2024-04-01),'CAN',max))

HINT 执行时间:

12秒对原来的28秒来说已经提升了很大的空间,但是客户表示不满意:ORACLE能秒出结果,到了达梦以后执行时间多了12倍,接受不了。

 无解,最后找到哥,看看能不能帮他让这条SQL"秒出结果"。

简单看了看,加索引和使用HINT都不好使,只能等价改写了,再创建合适的索引,让这条SQL走上新的索引。

等价改写 + 索引优化方案:

SELECT LI.STATUS,
FI.SOFL_SEQ_NR,
PI.CLAZZ,
PI.HV_TYPE
FROM LNF LI
INNER JOIN (SELECT ACT_DEP_CD,
FLT_DT,
SOFL_SEQ_NR,
DECODE(ALN_CD, 'OQ', 'CZ', ALN_CD) V1,
DECODE(ALN_CD, 'OQ', SUBSTR(
(SELECT CZ_FLT_NR FROM OQ_FLT_INFO OQ WHERE SUBSTR(OQ.OQ_FLT_NR, 3, 4) = FLT_NR), 3,
4), FLT_NR) V2
FROM FNF
WHERE FLT_DT = DATE'2024-04-01'
AND SCH_DEP_CD = 'CAN'
AND ROWNUM > 0) FI
ON LI.DEP_ARP_CD = FI.ACT_DEP_CD AND LI.FLT_DT = FI.FLT_DT AND LI.ALN_CD = FI.V1 AND
LI.FLT_NR = FI.V2
INNER JOIN (WITH PI AS (SELECT PSGR_ID, HV_TYPE, CLAZZ
FROM PNF) SELECT DISTINCT PSGR_ID, HV_TYPE, CLAZZ
FROM (SELECT PSGR_ID, HV_TYPE, CLAZZ
FROM PI
WHERE (PI.HV_TYPE IS NOT NULL)
UNION ALL
SELECT PSGR_ID, HV_TYPE, CLAZZ
FROM PI
WHERE PI.CLAZZ IN ('F', 'F1', 'J', 'C', 'D', 'I', 'O'))) PI ON LI.FK_PSGR_ID = PI.PSGR_ID
ORDER BY FI.SOFL_SEQ_NR; -- 加索引:
create index idx_pi_1_2 on PNF( PSGR_ID,CLAZZ,HV_TYPE );
create index idx_fi_1_2 on FNF ( act_dep_cd,FLT_DT );
CREATE index idx_1_2_3_FI on FNF(FLT_DT,SCH_DEP_CD,act_dep_cd,SOFL_SEQ_NR);
CREATE index idx_1_2_3_li on LNF(ALN_CD,dep_arp_cd,flt_nr,FLT_DT,FK_PSGR_ID,STATUS);
CREATE index idx_1_2_3 on FNF(FLT_DT,SCH_DEP_CD);

优化后执行计划:

#NSET2: [821, 385, 596]
2 #PIPE2: [821, 385, 596]
3 #PRJT2: [821, 385, 596]; exp_num(4), is_atom(FALSE)
4 #SORT3: [821, 385, 596]; key_num(1), is_distinct(FALSE), top_flag(0), is_adaptive(0)
5 #SLCT2: [820, 385, 596]; LI.FK_PSGR_ID = PI.PSGR_ID
6 #NEST LOOP INNER JOIN2: [820, 385, 596]; [with var]
7 #HASH2 INNER JOIN: [2, 385, 470]; KEY_NUM(4); KEY(FI.ACT_DEP_CD=LI.DEP_ARP_CD AND FI.FLT_DT=LI.FLT_DT AND FI.V1=LI.ALN_CD AND FI.V2=LI.FLT_NR) KEY_NULL_EQU(0, 0, 0, 0)
8 #NEST LOOP INDEX JOIN2: [2, 385, 470]
9 #ACTRL: [2, 385, 470];
10 #PRJT2: [1, 385, 235]; exp_num(5), is_atom(FALSE)
11 #RN: [1, 385, 235]
12 #BLKUP2: [1, 385, 235]; IDX_FLIGHT_INFO02(FNF)
13 #SSEK2: [1, 385, 235]; scan_type(ASC), IDX_FLIGHT_INFO02(FNF), scan_range[(exp_cast(2024-04-01),'CAN',min),(exp_cast(2024-04-01),'CAN',max))
14 #SSEK2: [1, 1, 235]; scan_type(ASC), IDX_1_2_3_LI(LNF as LI), scan_range[(FI.V1,FI.ACT_DEP_CD,FI.V2,FI.FLT_DT,min,min),(FI.V1,FI.ACT_DEP_CD,FI.V2,FI.FLT_DT,max,max))
15 #SSCN: [989, 6461936, 235]; IDX_1_2_3_LI(LNF as LI); btr_scan(1)
16 #PRJT2: [2, 1, 126]; exp_num(3), is_atom(FALSE)
17 #DISTINCT: [2, 1, 126]
18 #PRJT2: [1, 2, 126]; exp_num(3), is_atom(FALSE)
19 #UNION ALL: [1, 2, 126]
20 #PRJT2: [1, 1, 126]; exp_num(3), is_atom(FALSE)
21 #SLCT2: [1, 1, 126]; NOT(PNF.HV_TYPE IS NULL)
22 #BLKUP2: [1, 1, 126]; INDEX33555482(PNF)
23 #SSEK2: [1, 1, 126]; scan_type(ASC), INDEX33555482(PNF), scan_range[var4,var4]
24 #PRJT2: [1, 1, 126]; exp_num(3), is_atom(FALSE)
25 #HASH RIGHT SEMI JOIN2: [1, 1, 126]; n_keys(1) KEY(DMTEMPVIEW_889228539.colname=PNF.CLAZZ) KEY_NULL_EQU(0)
26 #CONST VALUE LIST: [1, 7, 48]; row_num(7), col_num(1)
27 #BLKUP2: [1, 1, 126]; INDEX33555482(PNF)
28 #SSEK2: [1, 1, 126]; scan_type(ASC), INDEX33555482(PNF), scan_range[var4,var4]
29 #SPL2: [1, 1, 96]; key_num(1), spool_num(0), is_atom(TRUE), has_var(1), sites(-)
30 #PRJT2: [1, 1, 96]; exp_num(1), is_atom(TRUE)
31 #BLKUP2: [1, 6, 96]; INDEX33555479(OQ)
32 #SLCT2: [1, 6, 96]; var3 = exp11
33 #SSCN: [1, 6, 96]; INDEX33555479(OQ_FLT_INFO as OQ); btr_scan(1)

执行时间:

通过改写+创建索引优化后,能做到像ORACLE这样,真"秒出结果"。

堆表和索引组织表的区别还是蛮大的,以前的老系统,业务SQL写得烂,用堆表跑问题不大,Oracle cbo算法牛逼也抗得住。

但是现在很多国产数据库都是使用索引组织表(IOT表),例如 OB、DM、TIDB 等国产数据库。

由于IOT表的特性在使用场景来说,对些老系统来说并不友好(老系统业务设计随意、业务逻辑较多在数据库层面实现),所以会产生很多性能问题:ORACLE 的索引都迁移到国产数据库了,性能还这么差,为什么没用上原来的索引啥的,等等诸如此类的问题。

要做国产化适配改造,并不能满足数据库功能、特性上的实现,业务模型也要配合整体来进行改造。

感谢各位读者同学能看到这里,如果有一些奇葩的SQL问题也可以联系我。

DM 传统行业SQL优化案例的更多相关文章

  1. SQL优化案例—— RowNumber分页

    将业务语句翻译成SQL语句不仅是一门技术,还是一门艺术. 下面拿我们程序开发工程师最常用的ROW_NUMBER()分页作为一个典型案例来说明. 先来看看我们最常见的分页的样子: WITH CTE AS ...

  2. mysql的sql优化案例

    前言 mysql的sql优化器比较弱,选择执行计划貌似很随机. 案例 一.表结构说明mysql> show create table table_order\G***************** ...

  3. SQL 优化案例 1

    create or replace procedure SP_GET_NEWEST_CAPTCHA( v_ACCOUNT_ID in VARCHAR2, --接收短信的手机号 v_Tail_num i ...

  4. SQL 优化案例

    create or replace procedure SP_GET_NEWEST_CAPTCHA( v_ACCOUNT_ID in VARCHAR2, --接收短信的手机号 v_Tail_num i ...

  5. 数栈SQL优化案例:隐式转换

    MySQL是当下最流行的关系型数据库之一,互联网高速发展的今天,MySQL数据库在电商.金融等诸多行业的生产系统中被广泛使用. 在实际的开发运维过程中,想必大家也常常会碰到慢SQL的困扰.一条性能不好 ...

  6. SQL夯实基础(四):子查询及sql优化案例

    首先我们先明确一下sql语句的执行顺序,如下有前至后执行: (1)from  (2) on   (3) join  (4) where  (5)group by  (6) avg,sum...  (7 ...

  7. sqlserver sql优化案例及思路

    始sql: SELECT TOP 100 PERCENT ZZ.CREW_NAME AS 机组, ZZ.CREW_ID, AA.年度时间, CC.当月时间, DD.连续七天时间 AS 最近七天 FRO ...

  8. 百倍性能的PL/SQL优化案例(r11笔记第13天)

    我相信你是被百倍性能的字样吸引了,不过我所想侧重的是优化的思路,这个比优化技巧更重要,而结果嘛,其实我不希望说成是百倍提升,“”自黑“”一下. 有一个真实想法和大家讨论一下,就是一个SQL语句如果原本 ...

  9. SQL 优化案例之变更表结构

    从慢日志报表中看到一条很长的SQL select id from myinfo and (( SUBSTRING_INDEX(location_axis, ) ) ) ), '$%') ) or ( ...

  10. 一则SQL优化案例

    原始sql: select CASE ) counts ,) else deadline end as deadline from t_product_credit) c group by sort ...

随机推荐

  1. 使用PdfSharp从模板生成Pdf文件

    ​ 最近在做一个生成文档的需求.通过先制作一个包含各字段占位符的文档模板,导入这个模板并填写内容替换掉占位符,再输出成最终文件. 由于版式固定,安全性更好,业务上常用Pdf作为最终标准化的格式, 在. ...

  2. notion database 必知必会

    notion database 必知必会 用过 mysql 的同学一定很容易上手 notion .在 notion 中,掌握好 database,基本上就掌握了 notion 最核心的概念. noti ...

  3. react build 后,打包后自动将index.html copy 404.html - create-react-app 创建的项目

    起因:build上传gitee,启用路由需要404.html自动跳转 当前环境 create-react-app 搭建的架子 解决方案 由于默认的时候把build.js打包,无法查看,只好eject ...

  4. Proxmark3入门指南

    Proxmark3笔记 --Proxmark3完全入门指南 写在前面 这里所有针对扇区.区块的计数都是从0开始算 一些需要知道的知识 为了能看懂笔记,需要能回答以下问题 ID卡和IC卡主要的区别是什么 ...

  5. Linux 运维工程师面试真题-3-Linux 磁盘及软件管理操作

    Linux 运维工程师面试真题-3-Linux 磁盘及软件管理操作 1.如何添加一块新的 50G 硬盘到 linux 服务器系统作为单独的分区,并正在使用?需要哪些 操作步骤? 2.有个金士顿 U 盘 ...

  6. [LeetCode] 2045. 到达目的地的第二短时间

    一.摘要 本文介绍了一种使用BFS求无向图中第二短的距离的算法,本文算法参考自Python3 BFS找出第二短路径.通过使用BFS求出题目中给出的路径图(无向联通图)从节点1到节点n的第二短的路径,再 ...

  7. 检验实时3D像素流送平台好坏的七个标准!(下)

    上篇文章我们介绍了<检验实时3D像素流送平台质量的七个标准>中的前四个标准,本文我们将继续给您介绍检验像素流送平台质量的其他三个标准. 您的平台是通过云还是仅通过渲染的图像传输数据? 您的 ...

  8. 初探修模的三维模型OBJ格式轻量化压缩的遇到常见问题与处理方法

    初探修模的三维模型OBJ格式轻量化压缩的遇到常见问题与处理方法 在对经过修模的三维模型进行OBJ格式轻量化压缩处理的过程中,可能会遇到一些常见问题.以下是一些常见问题以及相应的处理方法: 1.顶点丢失 ...

  9. Python简单程序设计(计算程序设计(公式)篇)

    如题: 解题方式如下:

  10. struts2-66漏洞复现

    Strut2-66漏洞从搭建到复现到原理 0x0 创建JavaEE环境 使用idea创建JavaEE项目,添加Strut2的依赖 点击右上角创建新项目 下一步,依赖项只选择一个Servlet就行了,版 ...