Oracle SQL 'or' 的最佳化,最近的案例一則。
SQL Tuning之 OR的最佳化。
今天公司某Production DB時常LOADING飈起來,Monitor下發現一個很high的SQL:
SELECT COUNT(A.ISN) FROM MO_ROUTE A,MO B WHERE (A.ROUTE = :B2 OR A.ROUTE = 'LNBR') AND A.GRP = 'AI1' AND (A.MO LIKE 'NFPQ%' OR A.MO LIKE 'NF1Q%' OR A.MO LIKE 'NF6Q%') AND A.MO = B.MO(+) AND A.INTIME BETWEEN :B1 - 1 AND :B1 AND B.CDATE BETWEEN :B1 - 1 AND :B1
其PLAN如下:
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2195 Card=1 Bytes=49
)
1 0 SORT (AGGREGATE)
2 1 FILTER
3 2 NESTED LOOPS (Cost=2195 Card=1 Bytes=49)
4 3 PARTITION RANGE (ITERATOR)
5 4 PARTITION HASH (ALL)
6 5 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'MO_ROUTE
' (Cost=2194 Card=1 Bytes=30)
7 6 INDEX (RANGE SCAN) OF 'MO_ROUTE11' (NON-UNIQUE
) (Cost=1242 Card=1741)
8 3 TABLE ACCESS (BY INDEX ROWID) OF 'MO' (Cost=1 Card=1
Bytes=19)
9 8 INDEX (UNIQUE SCAN) OF 'MO1' (UNIQUE)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
39135 consistent gets
25654 physical reads
106180 redo size
521 bytes sent via SQL*Net to client
656 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
很好,很強大的Gets,這可是OLTP環境。
MO_ROUTE是一個RANGE-HASH Partitioned Table,INTIME作為進行RANGE的Column.從PLAN可以看出,經過了Partition Pruning,再走MO_ROUTE11這個INDEX。 MO_ROUTE11是一個Complex Index,以Intime為首列(Intime,section,grp)。看起來選則的比較有道理。
然而這個Table即使是一天的資料量也很大。這個時侯注意到MO,MO的可選擇性應該也是比較強的。
+HINT看一下:
SELECT /*+INDEX(A MO_ROUTE2)*/COUNT(A.ISN) FROM MO_ROUTE A,MO B WHERE
(A.ROUTE = 'VNMB'OR A.ROUTE = 'LNBR') AND A.GRP = 'AI1'
AND (A.MO LIKE 'NFPQ%' OR A.MO LIKE 'NF1Q%' OR A.MO LIKE 'NF6Q%')
AND A.MO = B.MO(+) AND A.INTIME BETWEEN sysdate - 1 AND sysdate
AND B.CDATE BETWEEN sysdate - 1 AND sysdate;
EXPLAN:
SELECT STATEMENT, GOAL = CHOOSE Cost=7414 Cardinality=1 Bytes=49
SORT AGGREGATE Cardinality=1 Bytes=49
CONCATENATION
FILTER
NESTED LOOPS Cost=85 Cardinality=1 Bytes=49
PARTITION RANGE ITERATOR
PARTITION HASH ALL
TABLE ACCESS BY LOCAL INDEX ROWID Object owner=TP Object name=MO_ROUTE Cost=84 Cardinality=1 Bytes=30
INDEX RANGE SCAN Object owner=TP Object name=MO_ROUTE2 Cost=66 Cardinality=17
TABLE ACCESS BY INDEX ROWID Object owner=TP Object name=MO Cost=1 Cardinality=1 Bytes=19
INDEX UNIQUE SCAN Object owner=TP Object name=MO1 Cardinality=1
FILTER
NESTED LOOPS Cost=85 Cardinality=1 Bytes=49
PARTITION RANGE ITERATOR
PARTITION HASH ALL
TABLE ACCESS BY LOCAL INDEX ROWID Object owner=TP Object name=MO_ROUTE Cost=84 Cardinality=1 Bytes=30
INDEX RANGE SCAN Object owner=TP Object name=MO_ROUTE2 Cost=66 Cardinality=17
TABLE ACCESS BY INDEX ROWID Object owner=TP Object name=MO Cost=1 Cardinality=1 Bytes=19
INDEX UNIQUE SCAN Object owner=TP Object name=MO1 Cardinality=1
FILTER
NESTED LOOPS Cost=85 Cardinality=1 Bytes=49
PARTITION RANGE ITERATOR
PARTITION HASH ALL
TABLE ACCESS BY LOCAL INDEX ROWID Object owner=TP Object name=MO_ROUTE Cost=84 Cardinality=1 Bytes=30
INDEX RANGE SCAN Object owner=TP Object name=MO_ROUTE2 Cost=66 Cardinality=17
TABLE ACCESS BY INDEX ROWID Object owner=TP Object name=MO Cost=1 Cardinality=1 Bytes=19
INDEX UNIQUE SCAN Object owner=TP Object name=MO1 Cardinality=1
COST變成7K多,而且實際過程中我只能把它CANCEL掉,否則Server Loading會一下子飆起來。
計劃裡只是到最後的總COST很高,單步的COST卻較小。
於是想到用Union All來替代OR:
---------------------------------------------------------------------
select sum(c.n) from
(SELECT COUNT(A.ISN) n FROM MO_ROUTE A,MO B WHERE
(A.ROUTE = 'VNMB' OR A.ROUTE = 'LNBR') AND A.GRP = 'AI1'
AND A.MO LIKE 'NFPQ%'
AND A.MO = B.MO(+) AND A.INTIME BETWEEN sysdate - 1 AND sysdate
AND B.CDATE BETWEEN sysdate - 1 AND sysdate
union all
SELECT COUNT(A.ISN) n FROM MO_ROUTE A,MO B WHERE
(A.ROUTE = 'VNMB' OR A.ROUTE = 'LNBR') AND A.GRP = 'AI1'
AND A.MO LIKE 'NF1Q%'
AND A.MO = B.MO(+) AND A.INTIME BETWEEN sysdate - 1 AND sysdate
AND B.CDATE BETWEEN sysdate - 1 AND sysdate
union all
SELECT COUNT(A.ISN) n FROM MO_ROUTE A,MO B WHERE
(A.ROUTE = 'VNMB' OR A.ROUTE = 'LNBR') AND A.GRP = 'AI1'
AND A.MO LIKE 'NF6Q%'
AND A.MO = B.MO(+) AND A.INTIME BETWEEN sysdate - 1 AND sysdate
AND B.CDATE BETWEEN sysdate - 1 AND sysdate) c
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=216 Card=1 Bytes=13)
1 0 SORT (AGGREGATE)
2 1 VIEW (Cost=216 Card=3 Bytes=39)
3 2 UNION-ALL
4 3 SORT (AGGREGATE)
5 4 FILTER
6 5 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'MO_ROUTE
' (Cost=69 Card=1 Bytes=30)
7 6 NESTED LOOPS (Cost=72 Card=1 Bytes=49)
8 7 TABLE ACCESS (BY INDEX ROWID) OF 'MO' (Cost=
3 Card=1 Bytes=19)
9 8 INDEX (RANGE SCAN) OF 'MO1' (UNIQUE) (Cost
=2 Card=1)
10 7 PARTITION RANGE (ITERATOR)
11 10 PARTITION HASH (ALL)
12 11 INDEX (RANGE SCAN) OF 'MO_ROUTE2' (NON-U
NIQUE) (Cost=65 Card=3)
13 3 SORT (AGGREGATE)
14 13 FILTER
15 14 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'MO_ROUTE
' (Cost=69 Card=1 Bytes=30)
16 15 NESTED LOOPS (Cost=72 Card=1 Bytes=49)
17 16 TABLE ACCESS (BY INDEX ROWID) OF 'MO' (Cost=
3 Card=1 Bytes=19)
18 17 INDEX (RANGE SCAN) OF 'MO1' (UNIQUE) (Cost
=2 Card=1)
19 16 PARTITION RANGE (ITERATOR)
20 19 PARTITION HASH (ALL)
21 20 INDEX (RANGE SCAN) OF 'MO_ROUTE2' (NON-U
NIQUE) (Cost=65 Card=3)
22 3 SORT (AGGREGATE)
23 22 FILTER
24 23 TABLE ACCESS (BY LOCAL INDEX ROWID) OF 'MO_ROUTE
' (Cost=69 Card=1 Bytes=30)
25 24 NESTED LOOPS (Cost=72 Card=1 Bytes=49)
26 25 TABLE ACCESS (BY INDEX ROWID) OF 'MO' (Cost=
3 Card=1 Bytes=19)
27 26 INDEX (RANGE SCAN) OF 'MO1' (UNIQUE) (Cost
=2 Card=1)
28 25 PARTITION RANGE (ITERATOR)
29 28 PARTITION HASH (ALL)
30 29 INDEX (RANGE SCAN) OF 'MO_ROUTE2' (NON-U
NIQUE) (Cost=65 Card=3)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2592 consistent gets
49 physical reads
1336 redo size
517 bytes sent via SQL*Net to client
656 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
COST降低到200多點,Buffer Gets和Physical reads大幅度減少。
Tuning的目標達成。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10856805/viewspace-1007639/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- SQL最佳化案例一則--複合索引沒有被使用SQL索引
- 最近幾個SQL最佳化案例(水一波部落格,當段子看😼😼)SQL
- oracle啟動案例一則Oracle
- Oracle某行系統SQL最佳化(案例四)OracleSQL
- SQL最佳化 | MySQL問題處理案例分享三則MySql
- Oracle某X系統SQL最佳化(案例六)OracleSQL
- Oracle SQL的最佳化[轉]OracleSQL
- Oracle SQL Like 的最佳化OracleSQL
- Oracle SQL*Loader使用案例(一)OracleSQL
- 34條簡單的SQL最佳化準則SQL
- 從一條巨慢SQL看基於Oracle的SQL最佳化SQLOracle
- SQL最佳化案例-正確的使用索引(二)SQL索引
- 基於Oracle的SQL最佳化OracleSQL
- 技術分享 | MySQL 覆蓋索引最佳化案例一則MySql索引
- 使用SQL Profile進行SQL最佳化案例SQL
- SQL最佳化案例-單表分頁語句的最佳化(八)SQL
- ORACLE SQL效能最佳化系列 (一) (轉)OracleSQL
- SQL解析時間過長的調整 案例一則 [複製連結]SQL
- SQL Command最佳化原則SQL
- 基於Oracle的sql最佳化(1)OracleSQL
- SQL最佳化案例-union代替or(九)SQL
- Oracle效能優化-SQL優化(案例一)Oracle優化SQL
- Oracle 某行系統SQL優化案例(一)OracleSQL優化
- Oracle 11.2.0.1.0升級到11.2.0.4.7案例一則Oracle
- oracle最佳化sql的內部過程OracleSQL
- Sql 巢狀迴圈最佳化案例SQL巢狀
- SQL最佳化案例-使用with as最佳化Subquery Unnesting(七)SQL
- SQL優化案例一則--複合索引沒有被使用SQL優化索引
- Oracle11gR2 RAC環境歸檔模式的配置案例一則Oracle模式
- 一個簡單的sql稽核案例SQL
- Oracle SQL效能最佳化OracleSQL
- Oracle sql 效能最佳化OracleSQL
- nginx的一些規則案例備忘Nginx
- Oracle_SQL部分_時間轉換(案例一)OracleSQL
- SQL最佳化案例-改變那些CBO無能為力的執行計劃(一)SQL
- Oracle修改主機名問題解決案例一則Oracle
- Oracle "腦殘" CBO 最佳化案例Oracle
- Sql最佳化(三) 關於oracle的併發SQLOracle