树形查询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 ...
随机推荐
- Linux 常用命令九 tar
一.tar命令 tar命令用于打包,解包. gzip命令用于压缩,解压缩. bzip2命令用于压缩,解压缩. 这三个是在linux中常用的,还有一些不常用的. tar打包: wang@wang:~/w ...
- bzoj 1680: [Usaco2005 Mar]Yogurt factory【贪心】
贪心,一边读入一边更新mn,用mn更新答案,mn每次加s #include<iostream> #include<cstdio> using namespace std; in ...
- Zygote和System进程的启动过程、Android应用进程启动过程
1.基本过程 init脚本的启动Zygote Zygote进程的启动 System进程的启动 Android应用进程启动过程 2.init脚本的启动 +------------+ +-------+ ...
- 1268 和为K的组合 Meet in mid二分思路
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1268&judgeId=193772 给出n = 20个数,问其是 ...
- RabbitMQ六:通过routingkey模拟日志
序言 本章文章进入深入了解RabbiMQ,平时项目中我们经常用到记录日志,常见的不外乎:Info.debug.warn.Error. 情境进入:先简单说一下我们需求,我们开发过程中会遇到很多日 ...
- 新奇:(nodejs兄弟)用HTML + FLASH +JS 也可以写桌面EXE。
首先看下面这张图片,下面的所有界面都是用html代码实现的. 编程IDE:vb6.0 使用控件:WEBBROWSER 原理:使用olelib 让程序继承:IDocHostUIHandler 和 ICu ...
- 基于C++11的call wrapper
要在C++中应用AOP,不像在其他的基于解释器的语言中那么方便,作为一种静态语言,如果给函数或者类的方法造一个wrapper,在wrapper里面嵌入调用前的代码和调用后的代码,也能达到一定程度的代码 ...
- 谈谈如何学习Linux操作系统
献给初学者:为了能把这篇不错的文章分享给大家.所以请允许我暂时用原创的形式展现给大家. @hcy 更多资源:http://blog.sina.com.cn/iihcy 一. 选择适合自己的linux ...
- 深度神经网络简述与Capsule介绍
本人最近初学Hinton大神的论文<Dynamic Routing Between Capsules >,对深度神经网络的内容进行了简要总结,将观看“从传统神经网络的角度解读Capsule ...
- 在死循环中使用Scanner获得键盘输入
1. 编译时无错误和警告,且运行过程中无异常的代码示例 //编译时无错误和警告,且运行过程中无异常的代码示例package scanner_test; import java.util.*; publ ...