树形查询SQL优化一例
上周五一哥们发了条SQL,让我看看,代码如下:
SELECT COUNT(1)
FROM (select m.sheet_id
from cpm_main_sheet_history m, cpm_service_warn_config s
where m.sheet_type_id in
(select t.row_id
from tbl_class_trees t
start with t.row_id = s.sheet_type_id
connect by t.parent_row_id = prior t.row_id)
and m.service_type in
(select tt.row_id
from tbl_class_trees tt
start with tt.row_id = s.business_type_id
connect by tt.parent_row_id = prior tt.row_id)
and m.accept_time >=
TO_CHAR(SYSDATE - time_interval / 24, 'yyyy-mm-dd hh24:mi:ss')
and s.row_id = 'AS170904165251'
and m.no_area in ('0000')) c__
--执行计划
PLAN_TABLE_OUTPUT
Plan hash value: 2710926849
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 143 | 96246 (1)| 00:19:15 |
|* 1 | FILTER | | | | | |
| 2 | NESTED LOOPS | | 1681 | 234K| 746 (1)| 00:00:09 |
| 3 | TABLE ACCESS BY INDEX ROWID | CPM_SERVICE_WARN_CONFIG | 1 | 56 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_CONFIG_ROW_ID | 1 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | CPM_MAIN_SHEET_HISTORY | 1681 | 142K| 745 (1)| 00:00:09 |
|* 6 | INDEX RANGE SCAN | IDX_CPM_NO_AREA_TIME1 | 449 | | 62 (0)| 00:00:01 |
|* 7 | FILTER | | | | | |
|* 8 | CONNECT BY NO FILTERING WITH SW (UNIQUE)| | | | | |
| 9 | TABLE ACCESS FULL | TBL_CLASS_TREES | 9527 | 493K| 113 (0)| 00:00:02 |
|* 10 | FILTER | | | | | |
|* 11 | CONNECT BY NO FILTERING WITH SW (UNIQUE)| | | | | |
| 12 | TABLE ACCESS FULL | TBL_CLASS_TREES | 9527 | 493K| 113 (0)| 00:00:02 |
----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT 0 FROM "TBL_CLASS_TREES" "T" WHERE "T"."ROW_ID"=:B1 START WITH "T"."ROW_ID"=:B2
CONNECT BY "T"."PARENT_ROW_ID"=PRIOR "T"."ROW_ID") AND EXISTS (SELECT 0 FROM "TBL_CLASS_TREES" "TT" WHERE
"TT"."ROW_ID"=:B3 START WITH "TT"."ROW_ID"=:B4 CONNECT BY "TT"."PARENT_ROW_ID"=PRIOR "TT"."ROW_ID"))
4 - access("S"."ROW_ID"='AS170904165251')
6 - access("M"."ACCEPT_TIME">=TO_CHAR(SYSDATE@!-"TIME_INTERVAL"/24,'yyyy-mm-dd hh24:mi:ss') AND
"M"."NO_AREA"='0000' AND "M"."ACCEPT_TIME" IS NOT NULL)
filter("M"."NO_AREA"='0000')
7 - filter("T"."ROW_ID"=:B1)
8 - access("T"."PARENT_ROW_ID"=PRIOR "T"."ROW_ID")
filter("T"."ROW_ID"=:B1)
10 - filter("TT"."ROW_ID"=:B1)
11 - access("TT"."PARENT_ROW_ID"=PRIOR "TT"."ROW_ID")
filter("TT"."ROW_ID"=:B1)
SQL优化前:
耗时:20s
count(1)返回: 147条数据
分析执行计划,执行计划中有filter关键字且有3个子级,这种sql是最容易引起性能问题的,所以第一时间是反应是sql有没有走索引,能不能改写。
尝试1:
建索引优化:
在TBL_CLASS_TREES表(row_id,parent_row_id)上建索引
执行计划:
PLAN_TABLE_OUTPUT
Plan hash value: 135779572
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 155 | 34147 (1)| 00:06:50 |
|* 1 | FILTER | | | | | |
| 2 | NESTED LOOPS | | 3021 | 457K| 816 (1)| 00:00:10 |
| 3 | TABLE ACCESS BY INDEX ROWID | CPM_SERVICE_WARN_CONFIG | 1 | 62 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_CONFIG_ROW_ID | 1 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | CPM_MAIN_SHEET_HISTORY | 3021 | 274K| 815 (1)| 00:00:10 |
|* 6 | INDEX RANGE SCAN | IDX_CPM_NO_AREA_TIME1 | 563 | | 136 (0)| 00:00:02 |
|* 7 | FILTER | | | | | |
|* 8 | CONNECT BY NO FILTERING WITH SW (UNIQUE)| | | | | |
| 9 | INDEX FAST FULL SCAN | IDX_ROW_ID | 9527 | 493K| 20 (0)| 00:00:01 |
|* 10 | FILTER | | | | | |
|* 11 | CONNECT BY NO FILTERING WITH SW (UNIQUE)| | | | | |
| 12 | INDEX FAST FULL SCAN | IDX_ROW_ID | 9527 | 493K| 20 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT 0 FROM "TBL_CLASS_TREES" "T" WHERE "T"."ROW_ID"=:B1 START WITH "T"."ROW_ID"=:B2
CONNECT BY "T"."PARENT_ROW_ID"=PRIOR "T"."ROW_ID") AND EXISTS (SELECT 0 FROM "TBL_CLASS_TREES" "TT" WHERE
"TT"."ROW_ID"=:B3 START WITH "TT"."ROW_ID"=:B4 CONNECT BY "TT"."PARENT_ROW_ID"=PRIOR "TT"."ROW_ID"))
4 - access("S"."ROW_ID"='AS170904165251')
6 - access("M"."ACCEPT_TIME">=TO_CHAR(SYSDATE@!-"TIME_INTERVAL"/24,'yyyy-mm-dd hh24:mi:ss') AND
"M"."NO_AREA"='0000' AND "M"."ACCEPT_TIME" IS NOT NULL)
filter("M"."NO_AREA"='0000')
7 - filter("T"."ROW_ID"=:B1)
8 - access("T"."PARENT_ROW_ID"=PRIOR "T"."ROW_ID")
filter("T"."ROW_ID"=:B1)
10 - filter("TT"."ROW_ID"=:B1)
11 - access("TT"."PARENT_ROW_ID"=PRIOR "TT"."ROW_ID")
filter("TT"."ROW_ID"=:B1)
--效果还是一样慢,此优化失败。
尝试2:
利用with改写sql优化
with t as (select /*+ materialize */ row_id,parent_row_id from tbl_class_trees)
SELECT COUNT(1)
FROM (select m.sheet_id
from cpm_main_sheet_history m,cpm_service_warn_config s
where m.sheet_type_id in
(select t.row_id
from t
start with t.row_id = s.sheet_type_id
connect by t.parent_row_id = prior t.row_id)
and m.service_type in
(select t.row_id
from t
start with t.row_id = s.business_type_id
connect by t.parent_row_id = prior t.row_id)
and m.accept_time >=
TO_CHAR(SYSDATE - time_interval / 24, 'yyyy-mm-dd hh24:mi:ss')
and s.row_id = 'AS170904165251'
and m.no_area in ('0000')) c__
--效果还是一样慢,此优化失败。
再次分析原SQL执行计划:
id=8,id=11的执行计划关键词是:CONNECT BY NO FILTERING WITH SW (UNIQUE)。
这个为树形查询在11g中的新特性,尝试让sql不使用这个新特性。
于是使用以下hint:/*+ connect_by_filtering */ 进行优化:
SELECT COUNT(1)
FROM (select m.sheet_id
from cpm_main_sheet_history m, cpm_service_warn_config s
where m.sheet_type_id in
(select /*+ connect_by_filtering */ t.row_id
from tbl_class_trees t
start with t.row_id = s.sheet_type_id
connect by t.parent_row_id = prior t.row_id)
and m.service_type in
(select /*+ connect_by_filtering */ tt.row_id
from tbl_class_trees tt
start with tt.row_id = s.business_type_id
connect by tt.parent_row_id = prior tt.row_id)
and m.accept_time >=
TO_CHAR(SYSDATE - time_interval / 24, 'yyyy-mm-dd hh24:mi:ss')
and s.row_id = 'AS170904165251'
and m.no_area in ('0000')) c__
PLAN_TABLE_OUTPUT
Plan hash value: 2824841339
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 246 | 188K (1)| 00:37:47 |
|* 1 | FILTER | | | | | |
| 2 | NESTED LOOPS | | 3021 | 725K| 816 (1)| 00:00:10 |
| 3 | TABLE ACCESS BY INDEX ROWID | CPM_SERVICE_WARN_CONFIG | 1 | 106 | 1 (0)| 00:00:01 |
|* 4 | INDEX UNIQUE SCAN | PK_CONFIG_ROW_ID | 1 | | 0 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID | CPM_MAIN_SHEET_HISTORY | 3021 | 413K| 815 (1)| 00:00:10 |
|* 6 | INDEX RANGE SCAN | IDX_CPM_NO_AREA_TIME1 | 563 | | 136 (0)| 00:00:02 |
|* 7 | FILTER | | | | | |
|* 8 | CONNECT BY WITH FILTERING | | | | | |
| 9 | TABLE ACCESS BY INDEX ROWID| TBL_CLASS_TREES | 1 | 107 | 2 (0)| 00:00:01 |
|* 10 | INDEX UNIQUE SCAN | PK_TBL_CLASS_TREESS | 1 | | 1 (0)| 00:00:01 |
|* 11 | HASH JOIN | | | | | |
| 12 | CONNECT BY PUMP | | | | | |
| 13 | TABLE ACCESS FULL | TBL_CLASS_TREES | 6 | 318 | 113 (0)| 00:00:02 |
|* 14 | FILTER | | | | | |
|* 15 | CONNECT BY WITH FILTERING | | | | | |
| 16 | TABLE ACCESS BY INDEX ROWID| TBL_CLASS_TREES | 1 | 107 | 2 (0)| 00:00:01 |
|* 17 | INDEX UNIQUE SCAN | PK_TBL_CLASS_TREESS | 1 | | 1 (0)| 00:00:01 |
|* 18 | HASH JOIN | | | | | |
| 19 | CONNECT BY PUMP | | | | | |
| 20 | TABLE ACCESS FULL | TBL_CLASS_TREES | 6 | 318 | 113 (0)| 00:00:02 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT /*+ CONNECT_BY_FILTERING */ 0 FROM "TBL_CLASS_TREES" "T" WHERE
"T"."ROW_ID"=:B1 START WITH "T"."ROW_ID"=:B2) AND EXISTS (SELECT /*+ CONNECT_BY_FILTERING */ 0
FROM "TBL_CLASS_TREES" "TT" WHERE "TT"."ROW_ID"=:B3 START WITH "TT"."ROW_ID"=:B4))
4 - access("S"."ROW_ID"='AS170904165251')
6 - access("M"."ACCEPT_TIME">=TO_CHAR(SYSDATE@!-"TIME_INTERVAL"/24,'yyyy-mm-dd hh24:mi:ss')
AND "M"."NO_AREA"='0000' AND "M"."ACCEPT_TIME" IS NOT NULL)
filter("M"."NO_AREA"='0000')
7 - filter("T"."ROW_ID"=:B1)
8 - access("T"."PARENT_ROW_ID"=PRIOR "T"."ROW_ID")
10 - access("T"."ROW_ID"=:B1)
11 - access("T"."PARENT_ROW_ID"=PRIOR "T"."ROW_ID")
14 - filter("TT"."ROW_ID"=:B1)
15 - access("TT"."PARENT_ROW_ID"=PRIOR "TT"."ROW_ID")
17 - access("TT"."ROW_ID"=:B1)
18 - access("TT"."PARENT_ROW_ID"=PRIOR "TT"."ROW_ID")
--优化后,SQL能在5s返回结果
树形查询SQL优化一例的更多相关文章
- 跨服务器查询sql语句样例
若2个数据库在同一台机器上:insert into DataBase_A..Table1(col1,col2,col3----)select col11,col22,col33-- from Data ...
- 跨服务器查询sql语句样例(转)
若2个数据库在同一台机器上: insert into DataBase_A..Table1(col1,col2,col3----) select col11,col22,col33-- from Da ...
- oracle 11g亿级复杂SQL优化一例(数量级性能提升)
自从16年之后,因为工作原因,项目中就没有再使用oracle了,最近最近支持一个项目,又要开始负责这块事情了.最近在跑性能测试,配置全部调好之后,不少sql还存在性能低下的问题,主要涉及执行计划的不合 ...
- 查询SQL优化
SQL优化的一般步骤 通过show status命令了解各种SQL的执行频率定位执行效率较低的SQL语句,重点select通过explain分析低效率的SQL确定问题并采取相应的优化措施 优化措施 s ...
- 反连接NOT EXISTS子查询中有or 谓词连接条件SQL优化一例
背景 今天在日常数据库检查中,发现一SQL运行时间特别长,于是抓取出来,进行优化. 优化前: 耗时:503s 返回:0 SQL代码 SELECT * FROM MM_PAYABLEMONEY_TD P ...
- 1 min 数据查询 SQL 优化
问题 前几天线上数据库 IOPS 飙升,一直居高不下,最近并没有升级.遂查看数据库正在执行的 SQL 语句,发现有个查询离线设备的语句极其缓慢. 探寻原因 SELECT o.* FROM ( SELE ...
- mysql联合查询sql优化
我们在使用mysql数据库时,经常会使用到mysql的联合查询,联合查询分为内连接和外连接,内连接查询结果是联合的表都存在匹配才会有结果,外连接则根据驱动表是否存在匹配来生成结果集. 这里使用mysq ...
- oracle查询SQL优化相当重要
如果表中的时间字段是索引,那么时间字段不要使用函数,函数会使索引失效. 例如: select * from mytable where trunc(createtime)=trunc(sysdate) ...
- Mysql 分页查询sql优化
先查下数据表的总条数: SELECT COUNT(id) FROM ts_translation_send_address 执行分页界SQL 查看使用时间2.210s SELECT * FROM ts ...
随机推荐
- html语义化与前端页面排版规则
1.使用div进行布局,不要用div进行无意义的包裹 span行内常见元素 2.可以使用div和p的情况下,尽量用p.p有默认上下间隔字体加粗等,可以对终端有适配 3.需要强调的文本,可以包含在st ...
- NOIp 2014 寻找道路【图的遍历/最短路】By cellur925
题目传送门 比较裸的图论,结果自己还是没做出来,我真菜. 我们根据题意,只要把不能通向终点的点求出,然后再分别以这些点为起点,求出它们能到达的点,这些点也不能在路径上. 之后跑一个最短路即可. 注意以 ...
- Java之简单的四则运算
简单的四则运算 请你编写程序实现能处理两个数的+.-.*./.%的表达式程序.数据的输入/输出全部使用标准输入/输出,输入数据的第一行为你需要计算表达式的个数,从第2行开始,每一行为你计算的一个表达式 ...
- 全选Js
<th><input type="checkbox" value="" id="checkedAll" onclick=& ...
- Linux 虚拟机配置网络
- 区间DP UVA 10739 String to Palindrome
题目传送门 /* 题意:三种操作,插入,删除,替换,问最少操作数使得字符串变成回文串 区间DP:有一道类似的题,有点不同的是可以替换,那么两端点不同的时候可以替换掉一个后成回文, 即dp[j+1][k ...
- "HIBERNATE_SEQUENCE" does not exist问题处理
JavaWeb应用在MySQL环境下可以正常运行,数据迁移至Oracle或者人大金仓后应用运行爆出如下错误: 严重: Servlet.service() for servlet [JeeCmsAdmi ...
- paint之Graphics
在paint方法里面,这个Graphics类就相当于一支画笔.而且就画在那个component里面,比如frame. 看例子代码: import java.awt.*; public class Te ...
- 写给W小姐的一封信
生活 琐碎 Hallo,Preaty.对于跟人说话,我很不擅长如何开头.我不知道什么样的开头是符合我在别人心目中我应有的形象.我不知道什么样的开头符合别人预想中与我相匹配的内容.或者说什么的开头才是一 ...
- AJPFX关于this用法和注意事项
this:代表对象.就是所在函数所属对象的引用.哪个对象调用了this所在的函数,this就代表哪个对象,就是哪个对象的引用.开发时在定义功能时,如果该功能内部使用到了调用该功能的对象,这时就用thi ...