树形查询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 ...
随机推荐
- Ubuntu 12.04的gnome classic panel添加程序快捷键(转载)
How to add applets to the Gnome classic panel in Ubuntu 12.04 转自:http://www.borfast.com/blog/how-add ...
- 洛谷 P4013 数字梯形问题【最大费用最大流】
第一问:因为每个点只能经过一次,所以拆点限制流量,建(i,i',1,val[i]),然后s向第一行建(s,i,1,0),表示每个点只能出发一次,然后最后一行连向汇点(i',t,1,0),跑最大费用最大 ...
- spoj 1693 COCONUTS - Coconuts【最小割】
s向所有信仰1的人连(s,i,1),所有信仰0的人连(i,t,1),对于朋友关系,连接双向边,流量为1.跑最大流的结果即为答案. 考虑这样做的意义.最小割就是把总点集分割为两个点集S,T,使得所有\( ...
- VS2013程序打包报 ISEXP : error -****: An error occurred streaming
原因缺少打包文件 解决方案: 找到打包文件 右击选择 downLoad selected item
- Luogu P1195/P1892 口袋的天空/BOI团伙 【最小生成树/并查集】By cellur925
其实这俩题挺水的,团伙拿下了一血,但是感觉还是写一下博客比较好x. 一.团伙 题目描述 1920年的芝加哥,出现了一群强盗.如果两个强盗遇上了,那么他们要么是朋友,要么是敌人.而且有一点是肯定的,就是 ...
- php 打包下载
<?php class zipfile { var $datasec = array (); var $ctrl_dir = array (); var $eof_ctrl_dir = &quo ...
- play framework
Compilation errorThe file {module:docviewer}/app/controllers/PlayDocumentation.java could not be com ...
- CMake学习笔记三:cmake 常用指令
1 基本指令 1,ADD_DEFINITIONS 向 C/C++编译器添加-D 定义,比如: DD_DEFINITIONS(-DENABLE_DEBUG -DABC),参数之间用空格分割. 如果你的代 ...
- 手把手教你玩微信小程序跳一跳
最近微信小程序火的半边天都红了,虽然不会写,但是至少也可以仿照网上大神开发外挂吧!下面手把手教妹纸们(汉纸们请自觉的眼观耳听)怎么愉快的在微信小游戏中获得高分. 废话不多说,咱们这就发车了!呸!咱们这 ...
- shell 2 解析
---- shell 3 /home/oracle/utility/macro/call_autopurge_arch.sh Description: Call purge archive log f ...