Oracle SQL 'or' 的优化,最近的案例一则。


Oracle 中or是可以用union/union all来作优化的

SQL Tuning OR的优化。

今天公司某Production DB时常LOADING飚起来,Monitor下发现一个很highSQL:

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

39135consistent gets

25654physical reads

106180redo size

521bytes sent via SQL*Net to client

656bytes 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 TableINTIME作为进行RANGEColumn.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 = CHOOSECost=7414Cardinality=1 Bytes=49

SORT AGGREGATECardinality=1Bytes=49

CONCATENATION

FILTER

NESTED LOOPSCost=85Cardinality=1 Bytes=49

PARTITION RANGE ITERATOR

PARTITION HASH ALL

TABLE ACCESS BY LOCAL INDEX ROWIDObject owner=TPObject name=MO_ROUTE Cost=84Cardinality=1 Bytes=30

INDEX RANGE SCANObject owner=TPObject name=MO_ROUTE2 Cost=66Cardinality=17

TABLE ACCESS BY INDEX ROWIDObject owner=TPObject name=MO Cost=1 Cardinality=1 Bytes=19

INDEX UNIQUE SCANObject owner=TPObject name=MO1 Cardinality=1

FILTER

NESTED LOOPSCost=85Cardinality=1 Bytes=49

PARTITION RANGE ITERATOR

PARTITION HASH ALL

TABLE ACCESS BY LOCAL INDEX ROWIDObject owner=TPObject name=MO_ROUTE Cost=84Cardinality=1 Bytes=30

INDEX RANGE SCANObject owner=TPObject name=MO_ROUTE2 Cost=66Cardinality=17

TABLE ACCESS BY INDEX ROWIDObject owner=TPObject name=MO Cost=1 Cardinality=1 Bytes=19

INDEX UNIQUE SCANObject owner=TPObject name=MO1 Cardinality=1

FILTER

NESTED LOOPSCost=85Cardinality=1 Bytes=49

PARTITION RANGE ITERATOR

PARTITION HASH ALL

TABLE ACCESS BY LOCAL INDEX ROWIDObject owner=TPObject name=MO_ROUTE Cost=84Cardinality=1 Bytes=30

INDEX RANGE SCANObject owner=TPObject name=MO_ROUTE2 Cost=66Cardinality=17

TABLE ACCESS BY INDEX ROWIDObject owner=TPObject name=MO Cost=1 Cardinality=1 Bytes=19

INDEX UNIQUE SCANObject owner=TPObject 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

2592consistent gets

49physical reads

1336redo size

517bytes sent via SQL*Net to client

656bytes 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 GetsPhysical reads大幅度减少。

Tuning的目标达成。

最新回复

曾经遇到过用这个方法从几小时优化到几分钟,但没有深究原因,也是分区表上的查询

作者 ignu 18 05 2010, 11:35

看我的思路流程:
我想问题是出在or的内部处理上,CONCATENATION.

作者 Karsus 21 05 2010, 09:02

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值