当前位置: 首页 > news >正文

一条sql语句的建议调优分析(r5笔记第73天)

前几天开发的同事问我一个sql的问题,目前在测试环境中发现这条sql语句执行时间很长,希望我们能够给一些建议,能够尽快做一些改进。sql语句类似下面的形式。SELECT /*+ INDEX(ACCOUNT,ACCOUNT_PK)INDEX(ACCOUNT_EXT ACCOUNT_EXT_PK) */ ACCOUNT.ACCOUNT_ID, ACCOUNT.BE, ACCOUNT.CUSTOMER_NO, ACCOUNT.AR_BALANCE, ACCOUNT_EXT.CYCLE_CODE, ACCOUNT_EXT.CYCLE_MONTH, ACCOUNT_EXT.CYCLE_YEAR, TRX_LOG.MAX_TRX_ID, ACCOUNT.L3_AGREEMENT_ID, ACCOUNT_EXT.UNBILLED_OC_AMT, ACCOUNT_EXT.UB_PEND_CRD, ACCOUNT_EXT.BILLED_UNCONF_OC, ACCOUNT_EXT.BILLED_UNCONF_RC, ACCOUNT_EXT.BILLED_UNCONF_UC, NVL(DISPUTE_BALANCE, 0), ACCOUNT.L9_CRD_LMT_CALC_FORMULA FROM ACCOUNT, ACCOUNT_EXT, (SELECT /*+ NO_MERGE INDEX(TRANSACTION_LOG, TRANSACTION_LOG_1IX) PARALLEL(TRANSACTION_LOG, 8) */ MAX(TRANSACTION_ID) MAX_TRX_ID, ACCOUNT_ID FROM TRANSACTION_LOG WHERE ((TRANSACTION_ID >= :1 and sys_creation_date <= to_date(to_char(sysdate - :2 / 24 / 60 / 60, 'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss')) OR (TRANSACTION_ID >= :3 AND TRANSACTION_ID <= :4 AND DL_UPDATE_STAMP = 0)) and (TRANSACTION_LOG.PERIOD_KEY in (:5, :6, :7)) AND TRANSACTION_LOG.TRANS_TYPE IN (SELECT /*+ cardinality(1)*/ DISTINCT column_value as transType FROM table (SELECT CAST(:8 AS Varchar2Array_tp) FROM DUAL)) GROUP BY ACCOUNT_ID) TRX_LOG WHERE ACCOUNT.ACCOUNT_ID = TRX_LOG.ACCOUNT_ID AND ACCOUNT.ACCOUNT_ID = ACCOUNT_EXT.ACCOUNT_ID ORDER BY TRX_LOG.MAX_TRX_ID可以看出sql语句似乎是有调优的痕迹的,但是从执行计划来看,似乎还是有些地方出现了问题。执行计划如下:----------------------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |----------------------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 11076 | 941K| | 445K (1)| 01:29:05 | | || 1 | SORT ORDER BY | | 11076 | 941K| 1240K| 445K (1)| 01:29:05 | | || 2 | NESTED LOOPS | | | | | | | | || 3 | NESTED LOOPS | | 11076 | 941K| | 445K (1)| 01:29:02 | | || 4 | NESTED LOOPS | | 11076 | 594K| | 444K (1)| 01:28:49 | | || 5 | VIEW | | 11076 | 205K| | 442K (1)| 01:28:35 | | || 6 | HASH GROUP BY | | 11076 | 389K| | | | | || 7 | CONCATENATION | | | | | | | | || 8 | NESTED LOOPS | | 1510K| 51M| | 263K (1)| 00:52:39 | | || 9 | PARTITION RANGE INLIST | | 5549 | 184K| | 166K (1)| 00:33:21 |KEY(I) |KEY(I) ||* 10 | TABLE ACCESS BY LOCAL INDEX ROWID| TRANSACTION_LOG | 5549 | 184K| | 166K (1)| 00:33:21 |KEY(I) |KEY(I) ||* 11 | INDEX RANGE SCAN | TRANSACTION_LOG_1IX | 2436K| | | 1811 (1)| 00:00:22 |KEY(I) |KEY(I) ||* 12 | COLLECTION ITERATOR PICKLER FETCH | | 272 | 544 | | 17 (0)| 00:00:01 | | || 13 | FAST DUAL | | 1 | | | 2 (0)| 00:00:01 | | || 14 | NESTED LOOPS | | 1506K| 51M| | 179K (1)| 00:35:56 | | || 15 | PARTITION RANGE INLIST | | 5535 | 183K| | 83402 (1)| 00:16:41 |KEY(I) |KEY(I) ||* 16 | TABLE ACCESS BY LOCAL INDEX ROWID| TRANSACTION_LOG | 5535 | 183K| | 83402 (1)| 00:16:41 |KEY(I) |KEY(I) ||* 17 | INDEX RANGE SCAN | TRANSACTION_LOG_1IX | 1218K| | | 942 (1)| 00:00:12 |KEY(I) |KEY(I) ||* 18 | COLLECTION ITERATOR PICKLER FETCH | | 272 | 544 | | 17 (0)| 00:00:01 | | || 19 | FAST DUAL | | 1 | | | 2 (0)| 00:00:01 | | || 20 | TABLE ACCESS BY INDEX ROWID | ACCOUNT | 1 | 36 | | 1 (0)| 00:00:01 | | ||* 21 | INDEX UNIQUE SCAN | ACCOUNT_PK | 1 | | | 1 (0)| 00:00:01 | | ||* 22 | INDEX UNIQUE SCAN | AR9_ACCOUNT_EXT_PK | 1 | | | 1 (0)| 00:00:01 | | || 23 | TABLE ACCESS BY INDEX ROWID | AR9_ACCOUNT_EXT | 1 | 32 | | 1 (0)| 00:00:01 | | |----------------------------------------------------------------------------------------------------------------------------------------------对于这条语句的性能瓶颈还是在于下面的子查询,根据执行计划可以看到走了笛卡尔积。((TRANSACTION_ID >= :1 and sys_creation_date <= to_date(to_char(sysdate - :2 / 24 / 60 / 60, 'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss')) OR (TRANSACTION_ID >= :3 AND TRANSACTION_ID <= :4 AND DL_UPDATE_STAMP = 0))一般看到这个问题,感觉笛卡尔积性能是非常差的,这个也是相对的。至少从谓词信息来看,优化器还是在内部做了不少的工作,不能直接就说笛卡尔积是低效的。对于笛卡尔积的情况,在itpub中也有一些帖子有相关的讨论,可以参考。http://www.itpub.net/thread-1511375-4-1.htmlPredicate Information (identified by operation id):--------------------------------------------------- 9 - filter(("TRANSACTION_LOG"."PERIOD_KEY"=:5 OR "TRANSACTION_LOG"."PERIOD_KEY"=:6 OR "TRANSACTION_LOG"."PERIOD_KEY"=:7) AND ("TRANSACTION_ID">=:1 AND "SYS_CREATION_DATE"<=TO_DATE(TO_CHAR(SYSDATE@!-:2/24/60/60,'yyyy-mm-dd hh24:mi:ss'),'yyyy-mm-dd hh24:mi:ss') OR "TRANSACTION_ID">=:3 AND "TRANSACTION_ID"<=:4 AND "DL_UPDATE_STAMP"=0)) 14 - access("TRANSACTION_ID">=:3 AND "TRANSACTION_ID"<=:4) filter("TRANSACTION_ID"<=:4 AND "TRANSACTION_ID">=:3) 17 - access("TRANSACTION_ID">=:1) filter("TRANSACTION_ID">=:1) 18 - filter("TRANSACTION_LOG"."TRANS_TYPE"=VALUE(KOKBF$)) 21 - access("ACCOUNT"."ACCOUNT_ID"="TRX_LOG"."ACCOUNT_ID") 22 - access("ACCOUNT"."ACCOUNT_ID"="ACCOUNT_EXT"."ACCOUNT_ID")对于这条语句的调优来说,尽管空间很小,但是还有一些改进的地方。从调优的Hint来看,有些hint其实是没有使用到的,比如并行的hint,其实这个时候还是能够合理利用起来。改为 parallel_index PARALLEL_INDEX(TRANSACTION_LOG, 8)接着就是性能瓶颈的过滤条件了,其实过滤条件中最好还是能够有一个范围id的情况,比如(transaction_id >= and transaction_id <=xx 这种情况要比只是指定transaction_id>=xxx要好很多,而且可控性要好很多。所以对于过滤条件啊的部分,建议是 (transaction >= and transaction <=xx)的形式。最后是一个补充的建议,即关键的表TRANSACTION_LOG 是一个分区表,所以可以尽可能的使用分区键值。TABLE_NAME PARTITION PARTITION_COUNT COLUMN_LIST PART_COUNTS SUBPAR_COUNT STATUS修改后的语句如下:SELECT /*+ INDEX(ACCOUNT,ACCOUNT_PK)INDEX(ACCOUNT_EXT ACCOUNT_EXT_PK) */ACCOUNT.ACCOUNT_ID,ACCOUNT.BE,ACCOUNT.CUSTOMER_NO,ACCOUNT.AR_BALANCE,ACCOUNT_EXT.CYCLE_CODE,ACCOUNT_EXT.CYCLE_MONTH,ACCOUNT_EXT.CYCLE_YEAR,TRX_LOG.MAX_TRX_ID,ACCOUNT.L3_AGREEMENT_ID,ACCOUNT_EXT.UNBILLED_OC_AMT,ACCOUNT_EXT.UB_PEND_CRD,ACCOUNT_EXT.BILLED_UNCONF_OC,ACCOUNT_EXT.BILLED_UNCONF_RC,ACCOUNT_EXT.BILLED_UNCONF_UC,NVL(DISPUTE_BALANCE, 0),ACCOUNT.L9_CRD_LMT_CALC_FORMULA FROM ACCOUNT, ACCOUNT_EXT, (SELECT /*+ INDEX(TRANSACTION_LOG, TRANSACTION_LOG_1IX) PARALLEL_INDEX(TRANSACTION_LOG, 8) */ MAX(TRANSACTION_ID) MAX_TRX_ID, ACCOUNT_ID FROM TRANSACTION_LOG WHERE ((TRANSACTION_ID >= :1 and TRANSACTION_ID <= :4 and sys_creation_date <= to_date(to_char(sysdate - :2 / 24 / 60 / 60, 'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss')) OR (TRANSACTION_ID >= :3 AND TRANSACTION_ID <= :4 AND DL_UPDATE_STAMP = 0)) and (TRANSACTION_LOG.PERIOD_KEY in (:5, :6, :7)) and TRANSACTION_LOG.partition_id in () AND TRANSACTION_LOG.TRANS_TYPE IN (SELECT /*+cardinality(1)*/ DISTINCT column_value as transType FROM table (SELECT CAST(:8 AS Varchar2Array_tp) FROM DUAL)) GROUP BY ACCOUNT_ID) TRX_LOGWHERE ACCOUNT.ACCOUNT_ID = TRX_LOG.ACCOUNT_ID AND ACCOUNT.ACCOUNT_ID = ACCOUNT_EXT.ACCOUNT_IDORDER BY TRX_LOG.MAX_TRX_id修改后的执行计划如下:Execution plan as below.---------------------------------------------------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | TQ |IN-OUT| PQ Distrib |---------------------------------------------------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | 530 | 46110 | 24465 (1)| 00:04:54 | | | | | || 1 | SORT ORDER BY | | 530 | 46110 | 24465 (1)| 00:04:54 | | | | | || 2 | NESTED LOOPS | | | | | | | | | | || 3 | NESTED LOOPS | | 530 | 46110 | 24464 (1)| 00:04:54 | | | | | || 4 | NESTED LOOPS | | 530 | 29150 | 24457 (1)| 00:04:54 | | | | | || 5 | VIEW | | 530 | 10070 | 176K (87)| 00:35:13 | | | | | || 6 | HASH GROUP BY | | 530 | 20670 | | | | | | | || 7 | CONCATENATION | | | | | | | | | | || 8 | NESTED LOOPS | | 6867 | 261K| 83837 (1)| 00:16:47 | | | | | || 9 | PX COORDINATOR | | | | | | | | | | || 10 | PX SEND QC (RANDOM) | :TQ10000 | 25 | 925 | 83400 (1)| 00:16:41 | | | Q1,00 | P->S | QC (RAND) || 11 | PX PARTITION RANGE INLIST | | 25 | 925 | 83400 (1)| 00:16:41 |KEY(I) |KEY(I) | Q1,00 | PCWC | ||* 12 | TABLE ACCESS BY LOCAL INDEX ROWID| TRANSACTION_LOG | 25 | 925 | 83400 (1)| 00:16:41 |KEY(I) |KEY(I) | Q1,00 | PCWP | ||* 13 | INDEX RANGE SCAN | TRANSACTION_LOG_1IX | 1218K| | 942 (1)| 00:00:12 |KEY(I) |KEY(I) | Q1,00 | PCWP | ||* 14 | COLLECTION ITERATOR PICKLER FETCH | | 272 | 544 | 17 (0)| 00:00:01 | | | | | || 15 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | | | || 16 | NESTED LOOPS | | 137K| 5229K| 92165 (1)| 00:18:26 | | | | | || 17 | PX COORDINATOR | | | | | | | | | | || 18 | PX SEND QC (RANDOM) | :TQ20000 | 504 | 18648 | 83400 (1)| 00:16:41 | | | Q2,00 | P->S | QC (RAND) || 19 | PX PARTITION RANGE INLIST | | 504 | 18648 | 83400 (1)| 00:16:41 |KEY(I) |KEY(I) | Q2,00 | PCWC | ||* 20 | TABLE ACCESS BY LOCAL INDEX ROWID| TRANSACTION_LOG | 504 | 18648 | 83400 (1)| 00:16:41 |KEY(I) |KEY(I) | Q2,00 | PCWP | ||* 21 | INDEX RANGE SCAN | TRANSACTION_LOG_1IX | 1218K| | 942 (1)| 00:00:12 |KEY(I) |KEY(I) | Q2,00 | PCWP | ||* 22 | COLLECTION ITERATOR PICKLER FETCH | | 272 | 544 | 17 (0)| 00:00:01 | | | | | || 23 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | | | | || 24 | TABLE ACCESS BY INDEX ROWID | ACCOUNT | 1 | 36 | 1 (0)| 00:00:01 | | | | | ||* 25 | INDEX UNIQUE SCAN | ACCOUNT_PK | 1 | | 1 (0)| 00:00:01 | | | | | ||* 26 | INDEX UNIQUE SCAN | ACCOUNT_EXT_PK | 1 | | 1 (0)| 00:00:01 | | | | | || 27 | TABLE ACCESS BY INDEX ROWID | ACCOUNT_EXT | 1 | 32 | 1 (0)| 00:00:01 | | | | | |---------------------------------------------------------------------------------------------------------------------------------------------------------

相关文章:

  • 泰国之旅随感(r1笔记第70天)
  • 曼谷周末游(r5笔记第74天)
  • 使用flashback query巧妙抽取指定数据(r5笔记第75天)
  • 数据刷新中的并行改进(二) (r5笔记第76天)
  • 养鱼生活的一段终结(r5笔记第77天)
  • oracle监控工具ignite使用图解(r5笔记第78天)
  • 数据刷新中的并行改进(三) (r5笔记第79天)
  • 浅谈exp/imp(上) (r5笔记第81天)
  • dataguard中MRP无法启动的问题分析和解决(r5笔记第82天)
  • tomcat源码编译和环境搭建(r5笔记第83天)
  • 浅谈exp/imp(下) (r5笔记第84天)
  • IT中的闰秒问题(r5笔记第85天)
  • 并行查询缓慢的问题分析(r5笔记第86天)
  • 关于ORA-01555的问题分析(r5笔记第87天)
  • 关于create database语句在10g,11g中的不同(r5笔记第88天)
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • C++入门教程(10):for 语句
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • ES6之路之模块详解
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • nodejs:开发并发布一个nodejs包
  • node入门
  • Object.assign方法不能实现深复制
  • opencv python Meanshift 和 Camshift
  • windows下使用nginx调试简介
  • 基于web的全景—— Pannellum小试
  • ------- 计算机网络基础
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 免费小说阅读小程序
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 收藏好这篇,别再只说“数据劫持”了
  • 学习ES6 变量的解构赋值
  • 异步
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • $ is not function   和JQUERY 命名 冲突的解说 Jquer问题 (
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (原創) 是否该学PetShop将Model和BLL分开? (.NET) (N-Tier) (PetShop) (OO)
  • (转) Android中ViewStub组件使用
  • (转)ORM
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .NET Micro Framework初体验
  • @GetMapping和@RequestMapping的区别
  • @ModelAttribute 注解
  • [1525]字符统计2 (哈希)SDUT
  • [2019.2.28]BZOJ4033 [HAOI2015]树上染色
  • [383] 赎金信 js
  • [Angular] 笔记 21:@ViewChild
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [CC-FNCS]Chef and Churu
  • [Codeforces] number theory (R1600) Part.11
  • [Excel]如何找到非固定空白格數列的條件數據? 以月份報價表單為例
  • [HarmonyOS]第一课:从简单的页面开始