您的位置:首页 > 数据库 > Oracle

Oracle隐式转换影响物化视图查询重写

2013-06-09 10:32 537 查看
今天有人问我一个物化视图查询重写的问题,最后发现问题其实和物化视图的功能没有多大的关系,而是隐式转换导致的问题。

还是通过例子来说明这个问题:

SQL> create table t (

2 id number,

3 time date,

4 other varchar2(4000))

5 partition by range (time)

6 (partition p1 values less than (to_date('2008-1-1', 'yyyy-mm-dd')),

7 partition p2 values less than (to_date('2009-1-1', 'yyyy-mm-dd')),

8 partition p3 values less than (to_date('2010-1-1', 'yyyy-mm-dd')),

9 partition p4 values less than (to_date('2011-1-1', 'yyyy-mm-dd')));

Table created.

SQL> insert into t

2 select rownum, sysdate - rownum, lpad('a', 4000, 'a')

3 from dba_objects;

76162 rows created.

SQL> create materialized view log on t

2 with rowid, sequence

3 (id, time)

4 including new values;

Materialized view log created.

SQL> create materialized view mv_t

2 refresh fast

3 enable query rewrite as

4 select time, count(*)

5 from t

6 group by time;

Materialized view created.

下面看看物化视图是否可以查询重写:

SQL> set autot on exp

SQL> select time, count(*)

2 from t

3 where time > to_date('2009-1-1', 'yyyy-mm-dd')

4 and time < to_date('2009-1-10', 'yyyy-mm-dd')

5 group by time;

TIME COUNT(*)

-------------- ----------

04-1月-09 1

09-1月-09 1

01-1月-09 1

05-1月-09 1

03-1月-09 1

02-1月-09 1

08-1月-09 1

07-1月-09 1

06-1月-09 1

9 rows selected.

Execution Plan

----------------------------------------------------------

Plan hash value: 1712400360

-------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 9 | 198 | 33 (4)| 00:00:01 |

|* 1 | MAT_VIEW REWRITE ACCESS FULL| MV_T | 9 | 198 | 33 (4)| 00:00:01 |

-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("MV_T"."TIME">TO_DATE('2009-01-01 00:00:00', 'yyyy-mm-dd

hh24:mi:ss') AND "MV_T"."TIME"

Note

-----

- dynamic sampling used for this statement

下面对基表进行DML操作,但是这个操作的结果并不会影响当前查询的分区:

SQL> set autot off

SQL> delete t where time < to_date('2008-1-1', 'yyyy-mm-dd');

75278 rows deleted.

SQL> commit;

Commit complete.

SQL> set autot on exp

SQL> select time, count(*)

2 from t

3 where time > to_date('2009-1-1', 'yyyy-mm-dd')

4 and time < to_date('2009-1-10', 'yyyy-mm-dd')

5 group by time;

TIME COUNT(*)

-------------- ----------

04-1月-09 1

09-1月-09 1

01-1月-09 1

05-1月-09 1

03-1月-09 1

02-1月-09 1

08-1月-09 1

07-1月-09 1

06-1月-09 1

9 rows selected.

Execution Plan

----------------------------------------------------------

Plan hash value: 1712400360

-------------------------------------------------------------------------------------

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |

-------------------------------------------------------------------------------------

| 0 | SELECT STATEMENT | | 9 | 198 | 33 (4)| 00:00:01 |

|* 1 | MAT_VIEW REWRITE ACCESS FULL| MV_T | 9 | 198 | 33 (4)| 00:00:01 |

-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

1 - filter("MV_T"."TIME">TO_DATE('2009-01-01 00:00:00', 'yyyy-mm-dd

hh24:mi:ss') AND "MV_T"."TIME"

Note

-----

- dynamic sampling used for this statement

可以看到,物化视图的PCT特性在这里显现出来,虽然物化视图和基表并不同步,但是由于Oracle进行修改分区并不是当前查询的分区,因此查询的数据在物化视图中仍然可以正确的得到,所以Oracle仍然选择了物化视图进行查询重写。

但是如果和上面链接的帖子的贴主一样使用隐式类型转换,则Oracle不再使用查询重写功能:

SQL> select time, count(*)

2 from t

3 where time > '01-1月-09'

4 and time < '10-1月-09'

5 group by time;

TIME COUNT(*)

-------------- ----------

04-1月-09 1

09-1月-09 1

01-1月-09 1

05-1月-09 1

03-1月-09 1

02-1月-09 1

08-1月-09 1

07-1月-09 1

06-1月-09 1

9 rows selected.

Execution Plan

----------------------------------------------------------

Plan hash value: 2676183194

--------------------------------------------------------------------------------------------

|Id| Operation |Name|Rows| Bytes | Cost (%CPU)| Time | Pstart| Pstop |

--------------------------------------------------------------------------------------------

| 0| SELECT STATEMENT | | 20| 180 | 64 (2)| 00:00:01 | | |

| 1| HASH GROUP BY | | 20| 180 | 64 (2)| 00:00:01 | | |

|*2| FILTER | | | | | | | |

| 3| PARTITION RANGE ITERATOR| | 20| 180 | 63 (0)| 00:00:01 | KEY | KEY |

|*4| TABLE ACCESS FULL |T | 20| 180 | 63 (0)| 00:00:01 | KEY | KEY |

--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter(TO_DATE('01-1月-09')

4 - filter("TIME">'01-1月-09' AND "TIME"<'10-1月-09')

Note

-----

- dynamic sampling used for this statement

SQL> select /*+ rewrite */ time, count(*)

2 from t

3 where time > '01-1月-09'

4 and time < '10-1月-09'

5 group by time;

TIME COUNT(*)

-------------- ----------

04-1月-09 1

09-1月-09 1

01-1月-09 1

05-1月-09 1

03-1月-09 1

02-1月-09 1

08-1月-09 1

07-1月-09 1

06-1月-09 1

9 rows selected.

Execution Plan

----------------------------------------------------------

Plan hash value: 2676183194

--------------------------------------------------------------------------------------------

|Id| Operation |Name|Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |

--------------------------------------------------------------------------------------------

| 0| SELECT STATEMENT | | 20| 180 | 64 (2)| 00:00:01 | | |

| 1| HASH GROUP BY | | 20| 180 | 64 (2)| 00:00:01 | | |

|*2| FILTER | | | | | | | |

| 3| PARTITION RANGE ITERATOR| | 20| 180 | 63 (0)| 00:00:01 | KEY | KEY |

|*4| TABLE ACCESS FULL |T | 20| 180 | 63 (0)| 00:00:01 | KEY | KEY |

--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter(TO_DATE('01-1月-09')

4 - filter("TIME">'01-1月-09' AND "TIME"<'10-1月-09')

Note

-----

- dynamic sampling used for this statement

可以看到,即使是使用REWRITE提示强制使用物化视图进行查询重写,Oracle仍然选择了表扫描。

其实道理很简单,由于使用了隐式类型转换,Oracle并不知道当前的查询是否需要访问被修改的分区,也就没有办法利用PCT的查询重写功能了。

根据Oracle的给出的信息发现,Oracle甚至不知道隐式转换后’01-1月-09'和'10-1月-09'的大小,为了保证SQL的正确性,还增加了过滤条件:filter(TO_DATE('01-1月-09')

又是一个说明隐式转换危害的例子,在写SQL的时候应该避免使用隐式转换,对当前的情况而言,隐式转换并不会造成任何的误解,但是可能会引发其他的问题。

oracle视频教程请关注:http://u.youku.com/user_video/id_UMzAzMjkxMjE2.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息