巧用rowid简化sql查询(r2笔记47天)
生产系统中有一条sql语句,目前执行的时间有点长了,而且看起来有些臃肿,客户问能不能改进一下。得到的sql语句如下:
SELECT COUNT(1)
FROM (
SELECT /*+ leading (payment_temp_table payment PAYMENT_DETAILS account memo) use_nl (payment_temp_table ar1_payment PAYMENT_DETAILS account memo) index (payment payment_pk) index (PAYMENT_DETAILS PAYMENT_DETAILS_pk) */
PAYMENT_DETAILS.PAYMENT_ID,
PAYMENT.CREDIT_ID,
PAYMENT.ACCOUNT_ID,
PAYMENT.AMOUNT,
PAYMENT.ORIGINAL_AMOUNT,
PAYMENT.ORIGINAL_CONVERTED_AMOUNT,
PAYMENT_DETAILS.PAYMENT_METHOD,
PAYMENT_DETAILS.DEPOSIT_DATE,
PAYMENT_DETAILS.CURRENCY,
PAYMENT_DETAILS.CHECK_NO,
PAYMENT_DETAILS.CREDIT_CARD_NUMBER,
PAYMENT_DETAILS.BANK_CODE,
PAYMENT_DETAILS.BANK_ACCOUNT_NUMBER,
ACCOUNT.ACCOUNT_TIMESTAMP,
ACCOUNT.CURRENCY,
PAYMENT_DETAILS.PAYMENT_SUB_METHOD,
ACCOUNT.BE,
MEMO.MEMO_TEXT,
PAYMENT_DETAILS.PERIOD_KEY,
PAYMENT_DETAILS.PARTITION_ID,
PAYMENT_DETAILS.AMOUNT,
PAYMENT.ACTIVITY_DATE,
PAYMENT_DETAILS.ACCOUNT_ID,
PAYMENT.L9_RT_ID,
PAYMENT_DETAILS.L9_CONV_INV_NUMBER,
PAYMENT_DETAILS.CC_EXPIRY_DATE,
PAYMENT_DETAILS.DIRECT_DEBIT_VOUCHER,
PAYMENT_DETAILS.PAYMENT_SOURCE_TYPE,
PAYMENT.L9_WHT_AMT,
PAYMENT.L9_WHT_CERT_NO,
PAYMENT.L9_WHT_RATE,
PAYMENT.L9_VAT_AMOUNT,
PAYMENT.L9_PRINT_RT_IND,
PAYMENT.L9_USER_ID,
PAYMENT.L9_RT_EXTRACT_IND,
PAYMENT.L9_ECA_REASON_CODE,
PAYMENT.L9_RT_GENERATE_MODE,
PAYMENT_DETAILS.L9_VAT_AMOUNT,
PAYMENT.BILL_SEQ_NO,
PAYMENT.ACTIVITY_INDICATOR,
ACCOUNT.L9_COMPANY_CODE,
PAYMENT_DETAILS.PAYMENT_SOURCE_ID,
PAYMENT.OPERATOR_ID
FROM PAYMENT_DETAILS,
PAYMENT,
ACCOUNT,
MEMO,
(SELECT row_number,
PAYMENT_ID,
CREDIT_ID,
ACCOUNT_ID,
PD_PARTITION_ID,
PD_PERIOD_KEY,
PT_PARTITION_ID,
PT_PERIOD_KEY
FROM (SELECT rownum as row_number,
PAYMENT_ID,
CREDIT_ID,
ACCOUNT_ID,
PD_PARTITION_ID,
PD_PERIOD_KEY,
PT_PARTITION_ID,
PT_PERIOD_KEY
FROM (SELECT /*+ leading (pt a pd) use_nl (pt a pd) index (pd PAYMENT_DETAILS_pk) */
DISTINCT PD.PAYMENT_ID,
PT.CREDIT_ID,
A.ACCOUNT_ID,
pd.partition_id pd_partition_id,
pd.period_key pd_period_key,
pt.partition_id pt_partition_id,
pt.period_key pt_period_key
FROM PAYMENT_DETAILS PD,
PAYMENT PT,
ACCOUNT A
WHERE PT.PARTITION_ID = A.PARTITION_ID
AND PT.ACCOUNT_ID = A.ACCOUNT_ID
AND PD.PARTITION_ID = PT.PYMDT_PARTITION_ID
AND PD.PERIOD_KEY = PT.PYMDT_PERIOD_KEY
AND PD.PAYMENT_ID = PT.PAYMENT_ID
AND (a.be IN
(SELECT child_be_id
FROM gn1_boh_relation
START WITH parent_be_id = NVL(0, 0)
CONNECT BY PRIOR
child_be_id = parent_be_id) OR
a.be = NVL(0, 0))
AND ROWNUM <= 2000
ORDER BY pt.ACTIVITY_DATE DESC,
pt.CREDIT_ID DESC))
WHERE row_number BETWEEN 1 AND 100) PAYMENT_TEMP_TABLE
WHERE PAYMENT_DETAILS.PAYMENT_ID = PAYMENT_TEMP_TABLE.PAYMENT_ID
AND PAYMENT_DETAILS.partition_id =
payment_temp_table.pd_partition_id
AND PAYMENT_DETAILS.period_key =
payment_temp_table.pd_period_key
AND ACCOUNT.account_id = payment_temp_table.account_id
AND PAYMENT.credit_id = payment_temp_table.credit_id
AND PAYMENT.partition_id = payment_temp_table.pt_partition_id
AND PAYMENT.period_key = payment_temp_table.pt_period_key
AND MEMO.memo_id(+) = PAYMENT_DETAILS.memo_id);
index的信息如下:
INDEX_NAME TABLESPACE INDEX_TYPE UNIQUENES PAR COLUMN_LIST TABLE_TYPE STATUS NUM_ROWS LAST_ANAL G
------------------------------ ---------- ---------- --------- --- ------------------------------ ---------- ------ ---------- --------- -
PAYMENT_DETAILS_PK NORMAL UNIQUE YES PAYMENT_ID,PARTITION_ID,PERIOD_KEY TABLE N/A 6718838 16-JUL-14 N ------------------------------ ---------- ---------- --------- --- ------------------------------ ---------- ------ ---------- --------- -
PAYMENT_PK NORMAL UNIQUE YES CREDIT_ID,PARTITION_ID,PERIOD_KEY TABLE N/A 6914026 16-JUL-14 N
可以看到基本索引在查询条件中能用都用到了,而且使用了hint,根据sql内容来看,这个查询只是需要得到对应的记录条数而已,是在原有的查询语句的基础上直接加了select count(1) from xxx改进的来的。 所以对于这类查询,就需要摆脱思想的束缚,可以最大程度上简化sql,达到同样的效果。 改进后的sql语句如下:
SELECT COUNT(1)
FROM (
SELECT
PAYMENT_DETAILS.rowid,
PAYMENT.rowid,
ACCOUNT.rowid ,
--AR1_MEMO.rowid
FROM PAYMENT_DETAILS,
PAYMENT,
ACCOUNT,
-- AR1_MEMO,
(SELECT pdrowid, ptrowid, arowid
FROM (SELECT rownum as row_number, pdrowid, ptrowid, arowid
FROM (SELECT /*+ leading (pt a pd) */
DISTINCT PD.rowid pdrowid,
PT.rowid ptrowid,
A.rowid arowid
FROM PAYMENT_DETAILS PD,
PAYMENT PT,
ACCOUNT A
WHERE PT.PARTITION_ID = A.PARTITION_ID
AND PT.ACCOUNT_ID = A.ACCOUNT_ID
AND PD.PARTITION_ID = PT.PYMDT_PARTITION_ID
AND PD.PERIOD_KEY = PT.PYMDT_PERIOD_KEY
AND PD.PAYMENT_ID = PT.PAYMENT_ID
AND (a.be IN
(SELECT child_be_id
FROM gn1_boh_relation
START WITH parent_be_id = NVL(0, 0)
CONNECT BY PRIOR
child_be_id = parent_be_id) OR
a.be = NVL(0, 0))
AND ROWNUM <= 2147483627
ORDER BY pt.ACTIVITY_DATE DESC,
pt.CREDIT_ID DESC))
WHERE row_number BETWEEN 1 AND 9223372036854775807) PAYMENT_TEMP_TABLE
WHERE PAYMENT_DETAILS.rowid = PAYMENT_TEMP_TABLE.pdrowid
AND ACCOUNT.rowid = payment_temp_table.arowid
AND PAYMENT.rowid = payment_temp_table.ptrowid
AND MEMO.memo_id(+) = PAYMENT_DETAILS.memo_id
直接通过rowid来做关联,因为不需要输出所有的数据,只要输出列出含有主键列,就可以考虑使用rowid来代替。 sql语句极大的简化了,不过还没有完,还可以考虑做点什么。因为memo这个表比较大,没有走主键,查询会走全表扫描,耗费不少时间,但是结果集中貌似也不是很需要,因为结果集只考虑最终的返回数据条数,可以考虑是否能够从查询中去掉这个表。 简单验证一下,模拟这种类似的外连接,看看结果集是否会有影响。
SQL>
insert into test_full values(1);
insert into test_full values(2);
insert into test_full values(3);
insert into test_partial values(1,'a');
insert into test_partial values(2,'b');
1 row created.
SQL>
1 row created.
SQL>
1 row created.
SQL>
1 row created.
SQL>
1 row created.
SQL>
SQL> select test_full.id, test_partial.name from test_full,test_partial
2 where test_partial.id(+) = test_full.id
3 /
ID NAME
---------- ------------------------------
1 a
2 b
3
通过上面的简单测试,可以说明,如果表test_full中含有的记录,通过和test_partial做外连接,也是全量输出test_full的值。 这样,可以考虑把memo表去除,整理后的sql语句简化为:
SELECT COUNT(1)
FROM (
SELECT
PAYMENT_DETAILS.rowid,
PAYMENT.rowid,
ACCOUNT.rowid
FROM PAYMENT_DETAILS,
PAYMENT,
ACCOUNT,
(SELECT pdrowid, ptrowid, arowid
FROM (SELECT rownum as row_number, pdrowid, ptrowid, arowid
FROM (SELECT /*+ leading (pt a pd) */
DISTINCT PD.rowid pdrowid,
PT.rowid ptrowid,
A.rowid arowid
FROM PAYMENT_DETAILS PD,
PAYMENT PT,
ACCOUNT A
WHERE PT.PARTITION_ID = A.PARTITION_ID
AND PT.ACCOUNT_ID = A.ACCOUNT_ID
AND PD.PARTITION_ID = PT.PYMDT_PARTITION_ID
AND PD.PERIOD_KEY = PT.PYMDT_PERIOD_KEY
AND PD.PAYMENT_ID = PT.PAYMENT_ID
AND (a.be IN
(SELECT child_be_id
FROM gn1_boh_relation
START WITH parent_be_id = NVL(0, 0)
CONNECT BY PRIOR
child_be_id = parent_be_id) OR
a.be = NVL(0, 0))
AND ROWNUM <= 2147483627
ORDER BY pt.ACTIVITY_DATE DESC,
pt.CREDIT_ID DESC))
WHERE row_number BETWEEN 1 AND 9223372036854775807) PAYMENT_TEMP_TABLE
WHERE PAYMENT_DETAILS.rowid = PAYMENT_TEMP_TABLE.pdrowid
AND ACCOUNT.rowid = payment_temp_table.arowid
AND PAYMENT.rowid = payment_temp_table.ptrowid
对于一些Hint也做了删减,保证不必要的资源消耗。 总之,性能sql,对于sql的简化也是一种考验,如果能够最大程度的简化,也是sql调优的进步。
- 二叉树的基本概念和遍历
- Java中MD5加密算法实现方法——附上具体代码
- 新手,Visual Studio 2015 配置Boost库,如何编译和选择,遇到无法打开文件“libboost_thread-vc140-mt-gd-1_63.lib“的解决办法
- Java中处理正则表达式的工具类——总有一个适合你
- 【Spark研究】用Apache Spark进行大数据处理第一部分:入门介绍
- “一切都是消息”--MSF(消息服务框架)入门简介
- 【Spark研究】用Apache Spark进行大数据处理第二部分:Spark SQL
- Android基础总结(2)——活动Activity
- Java实现的IP处理工具类——可用于项目
- 使用SQLServer同义词和SQL邮件,解决发布订阅中订阅库丢失数据的问题
- 一次误报引发的DNS检测方案的思考:DNS隧道检测平民解决方案
- Andriod基础——Adapter类
- ORM查询语言(OQL)简介--高级篇:脱胎换骨
- 用Java实现处理日期的工具类——常用日期处理方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- LeetCode98|判定字符是否唯一
- LeetCode97|合并两个有序链表
- LeetCode99|数组中出现次数超过一半的数字
- redis源码之hash结构的实现
- redis源码之set结构
- redis源码之zset结构的实现
- Elasticsearch: range 数据类型及基于range的聚合 (7.4发行版新功能)
- 漫画:如何在数组中找到和为 “特定值” 的三个数?
- 除了MySQL,大牛DBA还会啥?
- 用 Docker swarm 快速部署分布式图数据库 Nebula Graph 集群
- Labelhub 基于腾讯云 Serverless 技术为人工智能企业提供数据与模型解决方案
- 手把手教你使用 Prometheus 监控 JVM
- 基于云开发 CloudBase 搭建在线视频会议应用
- 手搓一个分布式大气监测系统(六)云端能力更新、说明及源码放出
- maybe incorrect parameters such as bit_rate, rate, width or height