不少人大概和我一样在创建物化视图的时候会犯头痛,怎样合理的改写SQL语句以及添加物化视图日志需要经过慎重精密的考虑。有了DBMS_ADVISOR.TUNE_MVIEW存储过程这个帮手后,极大地方便了DBA或应用设计人员创建和优化物化视图。该TUNE_MVIEW存储过程可以做到优化物化视图中的查询定义,修正物化视图日志的问题,此外它还能为原先不能refresh fast的物化视图提出建议以使得其可以快速刷新。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
SQL> 
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTS
  
2  USING 
INDEX 
REFRESH FAST 
ON 
DEMAND
  
3  ENABLE QUERY REWRITE
  
4  
AS 
select 
distinct 
t1,t2 
from 
MACLEAN.strb;
AS 
select 
distinct 
t1,t2 
from 
MACLEAN.strb
                                      
*
ERROR 
at 
line 4:
ORA-12015: cannot 
create 
a fast refresh materialized 
view 
from 
a complex query
 
 
/* 以
select 
distinct
查询语句为例,该语句本身不符合refresh fast的标准,但TUNE_MVIEW存储过程
    
可以将这种查询变形使得满足快速刷新的条件 */
 
--    PROCEDURE DBMS_ADVISOR.TUNE_MVIEW
--    PURPOSE: Tune a Create Materialized View statement to
--    ADVISOR SUPPORT:        SQL Access Advisor
--    PARAMETERS:
--         TASK_NAME
--            The user can pass in a user-defined task name or
--            get a returned system-generated task name.
--         MV_CREATE_STMT
--            CREATE MATERIALIZED VIEW SQL statement to tune
 
procedure 
tune_mview (task_name      
in 
out 
varchar2,
                      
mv_create_stmt 
in     
clob);
 
SQL> 
set 
serveroutput 
on
;
 
SQL> 
declare
  
2    tn varchar2(200);
  
3  
begin
  
4    DBMS_ADVISOR.TUNE_MVIEW(tn,
  
5                            mv_create_stmt => 
'CREATE MATERIALIZED VIEW MACLEAN.STRMTS
  
6                     USING INDEX REFRESH FAST ON DEMAND
  
7                     ENABLE QUERY REWRITE
  
8                     AS select distinct t1,t2 from MACLEAN.strb'
);
  
9    dbms_output.put_line(tn);
 
10  
end
;
 
11  /
TASK_484
 
PL/SQL 
procedure 
successfully completed.
 
SQL> 
select 
script_type,statement
  
2    
from 
dba_tune_mview
  
3   
where 
task_name = 
'TASK_484'
  
4   
order 
by 
action_id;
 
SCRIPT_TYPE    STATEMENT
 
IMPLEMENTATION 
CREATE 
MATERIALIZED 
VIEW 
LOG 
ON 
"MACLEAN"
.
"STRB" 
WITH 
ROWID, 
SEQUENCE 
(
"T1"
,
"T2"
)  INCLUDING NEW 
VALUES
IMPLEMENTATION 
ALTER 
MATERIALIZED 
VIEW 
LOG 
FORCE 
ON 
"MACLEAN"
.
"STRB" 
ADD 
ROWID, 
SEQUENCE 
(
"T1"
,
"T2"
)  INCLUDING NEW 
VALUES
IMPLEMENTATION 
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTS USING 
INDEX  
REFRESH FAST 
WITH 
ROWID ENABLE QUERY REWRITE 
AS 
SELECT 
MACLEAN.STRB.T2 C1, MACLEAN.STRB.T1 C2, 
COUNT
(*) M1 
FROM 
MACLEAN.STRB 
GROUP 
BY 
MACLEAN.STRB.T2, MACLEAN.STRB.T1
UNDO           
DROP 
MATERIALIZED 
VIEW 
MACLEAN.STRMTS
 
/* 可以看到TUNE_MVIEW存储过程将原查询变形为
SELECT
...
GROUP 
BY
的形式 */
 
SQL> 
CREATE 
MATERIALIZED 
VIEW 
LOG 
ON 
"MACLEAN"
.
"STRB" 
WITH 
ROWID, 
SEQUENCE 
(
"T1"
,
"T2"
)  INCLUDING NEW 
VALUES
;
Materialized 
view 
log created.
 
SQL> 
ALTER 
MATERIALIZED 
VIEW 
LOG 
FORCE 
ON 
"MACLEAN"
.
"STRB" 
ADD 
ROWID, 
SEQUENCE 
(
"T1"
,
"T2"
)  INCLUDING NEW 
VALUES
;
Materialized 
view 
log altered.
 
SQL> 
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTS USING 
INDEX  
REFRESH FAST 
WITH 
ROWID
ENABLE QUERY REWRITE 
AS 
SELECT 
MACLEAN.STRB.T2 C1, MACLEAN.STRB.T1 C2, 
COUNT
(*) M1
FROM 
MACLEAN.STRB 
GROUP 
BY 
MACLEAN.STRB.T2, MACLEAN.STRB.T1;
 
Materialized 
view 
created.
针对那些确实无法快速刷新的复杂查询,TUNE_MVIEW过程也可能给出将一个查询分解为多个物化视图达到快速刷新和查询重写的目的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
SQL> 
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTD
  
2  USING 
INDEX 
REFRESH FAST
  
3  
ON 
DEMAND ENABLE QUERY REWRITE 
AS
  
4  
select 
t2,t3,
count
(*) 
from 
strc 
group 
by 
t2,t3
  
5  
union 
all
  
6  
select 
t2,t3,
count
(*) 
from 
strd 
group 
by 
t2,t3;
select 
t2,t3,
count
(*) 
from 
strd 
group 
by 
t2,t3
                           
*
ERROR 
at 
line 6:
ORA-12015: cannot 
create 
a fast refresh materialized 
view 
from 
a complex query
 
 
SQL> 
set 
serveroutput 
on
;
SQL> 
declare
  
2    tn varchar2(200);
  
3  
begin
  
4    DBMS_ADVISOR.TUNE_MVIEW(tn,
  
5                            mv_create_stmt => 
'CREATE MATERIALIZED VIEW MACLEAN.STRMTC
  
6                                                   USING INDEX REFRESH FAST
  
7                                                   ON DEMAND ENABLE QUERY REWRITE AS
  
8                                                   select t2,t3,count(*) from strc group by t2,t3
  
9                                                   union all
 
10                                                  select t2,t3,count(*) from strd group by t2,t3'
);
 
11    dbms_output.put_line(tn);
 
12  
end
;
 
13  /
TASK_547
 
PL/SQL 
procedure 
successfully completed.
 
SQL> 
select 
statement
  
2    
from 
dba_tune_mview
  
3   
where 
task_name = 
'TASK_547'
  
4   
order 
by 
action_id;
 
CREATE 
MATERIALIZED 
VIEW 
LOG 
ON 
"MACLEAN"
.
"STRC" 
WITH 
ROWID, 
SEQUENCE 
(
"T2"
,
"T3"
)  INCLUDING NEW 
VALUES
ALTER 
MATERIALIZED 
VIEW 
LOG 
FORCE 
ON 
"MACLEAN"
.
"STRC" 
ADD 
ROWID, 
SEQUENCE 
(
"T2"
,
"T3"
)  INCLUDING NEW 
VALUES
CREATE 
MATERIALIZED 
VIEW 
LOG 
ON 
"MACLEAN"
.
"STRD" 
WITH 
ROWID, 
SEQUENCE 
(
"T2"
,
"T3"
)  INCLUDING NEW 
VALUES
ALTER 
MATERIALIZED 
VIEW 
LOG 
FORCE 
ON 
"MACLEAN"
.
"STRD" 
ADD 
ROWID, 
SEQUENCE 
(
"T2"
,
"T3"
)  INCLUDING NEW 
VALUES
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC$SUB1 USING 
INDEX  
REFRESH FAST 
WITH 
ROWID 
ON 
COMMIT 
ENABLE QUERY REWRITE 
AS 
SELECT 
MACLEAN.STRC.T3 C1, MACLEAN.STRC.T2 C2, 
COUNT
(*) M1 
FROM 
MACLEAN.STRC 
GROUP 
BY 
MACLEAN.STRC.T3, MACLEAN.STRC.T2
DROP 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC$SUB1
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC$SUB2 USING 
INDEX  
REFRESH FAST 
WITH 
ROWID 
ON 
COMMIT 
ENABLE QUERY REWRITE 
AS 
SELECT 
MACLEAN.STRD.T3 C1, MACLEAN.STRD.T2 C2, 
COUNT
(*) M1 
FROM 
MACLEAN.STRD 
GROUP 
BY 
MACLEAN.STRD.T3, MACLEAN.STRD.T2
DROP 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC$SUB2
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC USING 
INDEX  
REFRESH 
FORCE 
WITH 
ROWID ENABLE QUERY REWRITE 
AS  
(
SELECT 
"STRMTC$SUB1"
.
"C2" 
"T2"
,
"STRMTC$SUB1"
.
"C1" 
"T3"
,
"STRMTC$SUB1"
.
"M1" 
"COUNT(*)" 
FROM 
"MACLEAN"
.
"STRMTC$SUB1" 
"STRMTC$SUB1"
UNION 
ALL  
(
SELECT 
"STRMTC$SUB2"
.
"C2" 
"T2"
,
"STRMTC$SUB2"
.
"C1" 
"T3"
,
"STRMTC$SUB2"
.
"M1" 
"COUNT(*)" 
FROM 
"MACLEAN"
.
"STRMTC$SUB2" 
"STRMTC$SUB2"
)
DROP 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC
DBMS_ADVANCED_REWRITE.BUILD_SAFE_REWRITE_EQUIVALENCE (
'MACLEAN.STRMTC$RWEQ'
,
'select t2,t3,count(*) from strc group by t2,t3
                                                 
union all
                                                
select t2,t3,count(*) from strd group by t2,t3'
,
' (SELECT "STRMTC$SUB1"."C2" "T2","STRMTC$SUB1"."C1" "T3","STRMTC$SUB1"."M1" "COUNT(*)" FROM "MACLEAN"."STRMTC$SUB1" "STRMTC$SUB1") UNION ALL  (SELECT "STRMTC$SUB2"."C2" "T2","STRMTC$SUB2"."C1" "T3","STRMTC$SUB2"."M1" "COUNT(*)" FROM "MACLEAN"."STRMTC$SUB2" "STRMTC$SUB2")'
,600916906)
 
DBMS_ADVANCED_REWRITE.DROP_REWRITE_EQUIVALENCE(
'MACLEAN.STRMTC$RWEQ'
)
 
SQL> 
CREATE 
MATERIALIZED 
VIEW 
LOG 
ON 
"MACLEAN"
.
"STRC" 
WITH 
ROWID, 
SEQUENCE 
(
"T2"
,
"T3"
)  INCLUDING NEW 
VALUES
;
 
Materialized 
view 
log created.
 
SQL> 
ALTER 
MATERIALIZED 
VIEW 
LOG 
FORCE 
ON 
"MACLEAN"
.
"STRC" 
ADD 
ROWID, 
SEQUENCE 
(
"T2"
,
"T3"
)  INCLUDING NEW 
VALUES
;
 
Materialized 
view 
log altered.
 
SQL> 
CREATE 
MATERIALIZED 
VIEW 
LOG 
ON 
"MACLEAN"
.
"STRD" 
WITH 
ROWID, 
SEQUENCE 
(
"T2"
,
"T3"
)  INCLUDING NEW 
VALUES
;
 
Materialized 
view 
log created.
 
SQL> 
ALTER 
MATERIALIZED 
VIEW 
LOG 
FORCE 
ON 
"MACLEAN"
.
"STRD" 
ADD 
ROWID, 
SEQUENCE 
(
"T2"
,
"T3"
)  INCLUDING NEW 
VALUES
;
 
Materialized 
view 
log altered.
 
SQL> 
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC$SUB1 USING 
INDEX  
REFRESH FAST 
WITH 
ROWID
ON 
COMMIT 
ENABLE QUERY REWRITE 
AS 
SELECT 
MACLEAN.STRC.T3 C1, MACLEAN.STRC.T2 C2, 
COUNT
(*) M1
FROM 
MACLEAN.STRC 
GROUP 
BY 
MACLEAN.STRC.T3, MACLEAN.STRC.T2;
 
Materialized 
view 
created.
 
SQL> 
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC$SUB2 USING 
INDEX  
REFRESH FAST 
WITH 
ROWID
ON 
COMMIT 
ENABLE QUERY REWRITE 
AS 
SELECT 
MACLEAN.STRD.T3 C1, MACLEAN.STRD.T2 C2, 
COUNT
(*) M1
FROM 
MACLEAN.STRD 
GROUP 
BY 
MACLEAN.STRD.T3, MACLEAN.STRD.T2;
 
Materialized 
view 
created.
 
SQL> 
CREATE 
MATERIALIZED 
VIEW 
MACLEAN.STRMTC USING 
INDEX  
REFRESH 
FORCE 
WITH 
ROWID
ENABLE QUERY REWRITE 
AS
(
SELECT 
"STRMTC$SUB1"
.
"C2" 
"T2"
,
"STRMTC$SUB1"
.
"C1" 
"T3"
,
"STRMTC$SUB1"
.
"M1" 
"COUNT(*)" 
FROM 
"MACLEAN"
.
"STRMTC$SUB1" 
"STRMTC$SUB1"
)
UNION 
ALL
(
SELECT 
"STRMTC$SUB2"
.
"C2" 
"T2"
,
"STRMTC$SUB2"
.
"C1" 
"T3"
,
"STRMTC$SUB2"
.
"M1" 
"COUNT(*)" 
FROM 
"MACLEAN"
.
"STRMTC$SUB2" 
"STRMTC$SUB2"
);
 
Materialized 
view 
created.
 
declare
  
v_state varchar2(2000);
begin
  
select 
statement
    
into 
v_state
    
from 
dba_tune_mview
   
where 
task_name = 
'TASK_547'
     
and 
action_id = 15;
  
v_state := 
'begin ' 
|| v_state || 
'; end;'
;
  
dbms_output.put_line(v_state);
  
execute 
immediate v_state;
end
;
PL/SQL 
procedure 
successfully completed.
 
SQL> 
set 
linesize 200 pagesize 1400;
SQL> 
select 
t2,t3,
count
(*) 
from 
strc 
group 
by 
t2,t3
  
2  
union 
all
  
3  
select 
t2,t3,
count
(*) 
from 
strd 
group 
by 
t2,t3;
no 
rows 
selected
 
---------------------------------------------------------------------------------------------
| Id  | Operation                     | 
Name        
Rows  
| Bytes | Cost (%CPU)| 
Time     
|
---------------------------------------------------------------------------------------------
|   0 | 
SELECT 
STATEMENT              |             |     2 |    74 |     4  (50)| 00:00:01 |
|   1 |  
UNION
-
ALL                    
|             |       |       |            |          |
|   2 |   MAT_VIEW REWRITE ACCESS 
FULL
| STRMTC$SUB1 |     1 |    37 |     2   (0)| 00:00:01 |
|   3 |   MAT_VIEW REWRITE ACCESS 
FULL
| STRMTC$SUB2 |     1 |    37 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------
 
/* 可以看到查询成功被rewrite为对2个物化视图的扫描 */