下面的语句同样是生产环境的慢sql,通过我对大家的培训,把部分慢sql给当场干掉,成功阻止了双节点cpu偶尔过高的问题:
直接上当时的材料:
原始sql语句:
select sum(aaa.acceptid)
from (select count(c.accept_id) as acceptid
from cct_log_eomsintf_201503 c,
(select b.accept_id accept_id,
max(b.creation_time) creation_time
from cct_log_eomsintf_201503 b
where exists (select 1
from cct_log_eomsintf_201503 a
where a.exception_info like '%启动保障机制%'
and a.accept_id = b.accept_id)
group by b.accept_id) d,
cct_wf_accept_201503 e
where c.accept_id = d.accept_id
and c.creation_time = d.creation_time
and c.accept_id = e.accept_id
and e.ring <> 128
and e.ring <> 119
and c.exception_info like '%启动保障机制%'
union all
select count(c.accept_id) as acceptid
from cct_log_eomsintf_201504 c,
(select b.accept_id accept_id,
max(b.creation_time) creation_time
from cct_log_eomsintf_201504 b
where exists (select 1
from cct_log_eomsintf_201504 a
where a.exception_info like '%启动保障机制%'
and a.accept_id = b.accept_id)
group by b.accept_id) d,
cct_wf_accept_201504 e
where c.accept_id = d.accept_id
and c.creation_time = d.creation_time
and c.accept_id = e.accept_id
and e.ring <> 128
and e.ring <> 119
and c.exception_info like '%启动保障机制%') aaa
Execution Plan
----------------------------------------------------------
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 73783 (1)|
| 1 | SORT AGGREGATE | | 1 | 13 | |
| 2 | VIEW | | 2 | 26 | 73783 (1)|
| 3 | UNION-ALL | | | | |
| 4 | SORT AGGREGATE | | 1 | 24 | |
| 5 | VIEW | | 1 | 24 | 44412 (1)|
|* 6 | FILTER | | | | |
| 7 | HASH GROUP BY | | 1 | 134 | 44412 (1)|
|* 8 | HASH JOIN RIGHT SEMI | | 329K| 42M| 44399 (1)|
|* 9 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201503 | 20242 | 612K| 16662 (1)|
|* 10 | HASH JOIN | | 329K| 32M| 27735 (1)|
|* 11 | TABLE ACCESS BY INDEX ROWID| CCT_LOG_EOMSINTF_201503 | 1 | 51 | 8 (0)|
| 12 | NESTED LOOPS | | 3757 | 297K| 11074 (1)|
|* 13 | INDEX FAST FULL SCAN | IDX_CCT_WF_ACCEPT_201503 | 3331 | 99930 | 1069 (1)|
|* 14 | INDEX RANGE SCAN | ACCEPT_ID_IDX_201503 | 6 | | 2 (0)|
| 15 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201503 | 404K| 8697K| 16658 (1)|
| 16 | SORT AGGREGATE | | 1 | 24 | |
| 17 | VIEW | | 1 | 24 | 29371 (1)|
|* 18 | FILTER | | | | |
| 19 | HASH GROUP BY | | 1 | 120 | 29371 (1)|
|* 20 | HASH JOIN RIGHT SEMI | | 14719 | 1724K| 29370 (1)|
|* 21 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201504 | 11576 | 271K| 9536 (1)|
|* 22 | HASH JOIN | | 61608 | 5775K| 19832 (1)|
|* 23 | HASH JOIN | | 11575 | 836K| 10297 (1)|
|* 24 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201504 | 11576 | 497K| 9536 (1)|
|* 25 | INDEX FAST FULL SCAN | IDX_CCT_WF_ACCEPT_201504 | 22933 | 671K| 759 (1)|
| 26 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201504 | 231K| 4973K| 9534 (1)|
------------------------------------------------------------------------------------------------------
优化前:
select count(c.accept_id) as acceptid
from cct_log_eomsintf_201504 c,
(select b.accept_id accept_id, max(b.creation_time) creation_time
from cct_log_eomsintf_201504 b
where exists (select 1
from cct_log_eomsintf_201504 a
where a.exception_info like '%启动保障机制%'
and a.accept_id = b.accept_id)
group by b.accept_id) d,
cct_wf_accept_201504 e
where c.accept_id = d.accept_id
and c.creation_time = d.creation_time
and c.accept_id = e.accept_id
and e.ring <> 128
and e.ring <> 119
and c.exception_info like '%启动保障机制%'
Execution Plan
----------------------------------------------------------
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 24 | 29371 (1)|
| 1 | SORT AGGREGATE | | 1 | 24 | |
| 2 | VIEW | | 1 | 24 | 29371 (1)|
|* 3 | FILTER | | | | |
| 4 | HASH GROUP BY | | 1 | 120 | 29371 (1)|
|* 5 | HASH JOIN RIGHT SEMI | | 14719 | 1724K| 29370 (1)|
|* 6 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201504 | 11576 | 271K| 9536 (1)|
|* 7 | HASH JOIN | | 61608 | 5775K| 19832 (1)|
|* 8 | HASH JOIN | | 11575 | 836K| 10297 (1)|
|* 9 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201504 | 11576 | 497K| 9536 (1)|
|* 10 | INDEX FAST FULL SCAN| IDX_CCT_WF_ACCEPT_201504 | 22933 | 671K| 759 (1)|
| 11 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201504 | 231K| 4973K| 9534 (1)|
---------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
2 recursive calls
0 db block gets
139867 consistent gets
0 physical reads
768 redo size
515 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
分析:
很明显,CCT_LOG_EOMSINTF_201504表不应该被扫描三次,并且还是全表扫描。如果这个表非常大,在OLAP系统就容易搞死人了。
那么怎么想办法,只让CCT_LOG_EOMSINTF_201504被扫描一次呢?答案,使用with as的方式来优化。
优化后:
with t1 as
(select accept_id, creation_time, exception_info
from cct_log_eomsintf_201504
where exception_info like '%启动保障机制%')
select count(c.accept_id) as acceptid
from t1 c,
(select b.accept_id accept_id, max(b.creation_time) creation_time
from t1 b
where exists (select 1 from t1 a where a.accept_id = b.accept_id)
group by b.accept_id) d,
cct_wf_accept_201504 e
where c.accept_id = d.accept_id
and c.creation_time = d.creation_time
and c.accept_id = e.accept_id
and e.ring <> 128
and e.ring <> 119
优化后:
Execution Plan
---------------------------------------------------------
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
---------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 84 | 9580 (1)|
| 1 | TEMP TABLE TRANSFORMATION | | | | |
| 2 | LOAD AS SELECT | CCT_WF_ACCEPT_201504 | | | |
|* 3 | TABLE ACCESS FULL | CCT_LOG_EOMSINTF_201504 | 11576 | 361K| 9536 (1)|
| 4 | SORT AGGREGATE | | 1 | 84 | |
| 5 | NESTED LOOPS | | 1 | 84 | 44 (7)|
|* 6 | HASH JOIN | | 1 | 66 | 42 (8)|
| 7 | VIEW | | 11576 | 373K| 13 (0)|
| 8 | TABLE ACCESS FULL | SYS_TEMP_0FD9D69AB_7BCA41BF | 11576 | 361K| 13 (0)|
| 9 | VIEW | | 11576 | 373K| 28 (8)|
| 10 | HASH GROUP BY | | 11576 | 418K| 28 (8)|
|* 11 | HASH JOIN RIGHT SEMI | | 11576 | 418K| 27 (4)|
| 12 | VIEW | | 11576 | 158K| 13 (0)|
| 13 | TABLE ACCESS FULL | SYS_TEMP_0FD9D69AB_7BCA41BF | 11576 | 361K| 13 (0)|
| 14 | VIEW | | 11576 | 260K| 13 (0)|
| 15 | TABLE ACCESS FULL | SYS_TEMP_0FD9D69AB_7BCA41BF | 11576 | 361K| 13 (0)|
|* 16 | TABLE ACCESS BY INDEX ROWID| CCT_WF_ACCEPT_201504 | 1 | 18 | 2 (0)|
|* 17 | INDEX UNIQUE SCAN | PK_WFKACCEPT_AID_201504 | 1 | | 1 (0)|
---------------------------------------------------------------------------------------------------
Statistics
----------------------------------------------------------
123 recursive calls
11 db block gets
45740 consistent gets
1 physical reads
1768 redo size
515 bytes sent via SQL*Net to client
492 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
一致读取,从13w下降到4w。
还有像下面的sql,改写方式一致:
select count(*)
from (select t1.accept_id_1860, count(1)
from (select a.accept_id_1860, a.accept_id
from
cct_log_appealintf1860_201504 a
where not exists (select 1
from cct_wf_accept_201504 b
where a.accept_id = b.accept_id)
and
a.reqtype = '11') t1
group by t1.accept_id_1860
intersect
select t2.accept_id_1860, count(1)
from
cct_log_appealintf1860_201504 t2
where t2.accept_id_1860 in
(select a.accept_id_1860
from
cct_log_appealintf1860_201504 a
where not exists (select 1
from cct_wf_accept_201504 b
where a.accept_id = b.accept_id)
and
a.reqtype = '11')
and
t2.reqtype = '11'
group by t2.accept_id_1860) t3