树形查询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 ...
随机推荐
- Fiddler对https抓包时,提示"HTTPS decryption is disabled."原因及破解
Fiddler对https抓包时,提示"HTTPS decryption is disabled." 原因:没有启用 https 解密. 破解: ----------------- ...
- codeforces 880E. Maximum Subsequence(折半搜索+双指针)
E. Maximum Subsequence time limit per test 1 second memory limit per test 256 megabytes input standa ...
- 4800: [Ceoi2015]Ice Hockey World Championship(折半搜索)
4800: [Ceoi2015]Ice Hockey World Championship Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 622 S ...
- Luogu P2858 [USACO06FEB]奶牛零食Treats for the Cows 【区间dp】By cellur925
题目传送门 做完A Game以后找道区间dp练练手...结果这题没写出来(哭). 和A Game一样的性质,从两边取,但是竟然还有天数,鉴于之前做dp经常在状态中少保存一些东西,所以这次精心设计了状态 ...
- New Article For Test
\[ a ^ 2 + b ^ 2 ~-~ 2 \times a \times b \times cos~ \theta = c ^ 2 \] #include<stdio.h> int m ...
- 数学/找规律/暴力 Codeforces Round #306 (Div. 2) C. Divisibility by Eight
题目传送门 /* 数学/暴力:只要一个数的最后三位能被8整除,那么它就是答案:用到sprintf把数字转移成字符读入 */ #include <cstdio> #include <a ...
- 对数组随机赋值,并输出(Arrays.toString(arr))
import java.util.Arrays; public class Demo { public static void main(String[] args) { int[] arr = ne ...
- mybatis的mapper.xml文件细节
- Java数组的交集、并集
// 求两个数组的交集 public static int[] SameOfTwoArrays(int[] arr1, int[] arr2) { // 新建一个空数组,用于存储交集,空数组长度应该为 ...
- Android开发中使用startActivityForResult()方法从Activity A跳转Activity B出现B退出时A也同时退出的解决办法
最近一个 App 中用到了 startActivityForResult() 方法,使用的时候却出现了一些问题,比如我在 Activity A 中调用该方法向 Activity B 中跳转,如果 B ...