物化视图是一种特殊的物理表,“物化”(Materialized)视图是相对普通视图而言的。普通视图是虚拟表,应用的局限性大,任何对视图的查询,Oracle都实际上转换为视图SQL语句的查询。这样对整体查询性能的提高,并没有实质上的好处。
直接刷新
在scott用户下创建源数据表
create table scott.emp_ori
as
select empno, deptno,sal
from scott.emp
在ceno用户下创建MV
create materialized view ceno.mv_emp
build immediate
refresh on commit
--enable query rewrite
as
select empno, deptno,sal
from scott.emp
现在在源头数据表scott.ori作dml操作
drop table scott.emp_ori purge
create table scott.emp_ori
as
select empno, deptno,sal
from scott.emp where empno<2000
select * from scott.emp_ori
drop materialized view ceno.mv_emp
create materialized view ceno.mv_emp
build immediate
refresh on commit
enable query rewrite
as
select empno, deptno,sal
from scott.emp_ori
ORA-12054: 无法为实体化视图设置 ON COMMIT 刷新属性
alter table scott.emp_ori add constraintpk_emp_ori primary key (empno)
create materialized view ceno.mv_emp
build immediate
refresh on commit
enable query rewrite
as
select empno, deptno,sal
from scott.emp_ori
ok --成功创建 建立refresh on commit 需要源表上有主键存在? 等一会儿再进行讨论
看看原表与mv的数据
select empno,deptno,sal, '源数据' date_source from scott.emp_ori
union all
select empno,deptno,sal, '目标数据' date_source fromceno.mv_emp
无数据
insert into scott.emp_ori select
对源表进行DML操作
insert into scott.emp_ori
select empno, deptno,sal
from scott.emp where empno<7400
select empno,deptno,sal, '源数据' date_source from scott.emp_ori
union all
select empno,deptno,sal, '目标数据' date_source fromceno.mv_emp
commit;
select empno,deptno,sal, '源数据' date_source from scott.emp_ori
union all
select empno,deptno,sal, '目标数据' date_source fromceno.mv_emp
update scott.emp_ori set sal=600
select empno,deptno,sal, '源数据' date_source from scott.emp_ori
union all
select empno,deptno,sal, '目标数据' date_source fromceno.mv_emp
commit;
delete from scott.emp_ori
select empno,deptno,sal, '源数据' date_source from scott.emp_ori
union all
select empno,deptno,sal, '目标数据' date_source fromceno.mv_emp
commit;
select empno,deptno,sal, '源数据' date_source from scott.emp_ori
union all
select empno,deptno,sal, '目标数据' date_source fromceno.mv_emp
merge into scott.emp_ori t
using (select empno,deptno,sal from scott.emp where empno<7600) s
on (t.empno=s.empno)
when matched then
update set t.deptno=s.deptno, t.sal=s.sal
when not matched then
insert (t.empno,t.deptno,t.sal)
values(s.empno,s.deptno,s.sal)
select empno,deptno,sal, '源数据' date_source from scott.emp_ori
union all
select empno,deptno,sal, '目标数据' date_source fromceno.mv_emp
commit;
select empno,deptno,sal, '源数据' date_source from scott.emp_ori
union all
select empno,deptno,sal, '目标数据' date_source fromceno.mv_emp
看到源数据与目标数据在提交后,立即被一致化。
之前,我们说了,数据库commit实际上并没有多少工作要做,那怕之前的事物是一个很大的事物,commit也是瞬间完成工作。
但是有时候,提交却要需要很长时间,最有可能的原因是可能有一个MV建立在该表上,需要较长的时间将变化数据刷新到目标物化视图。
检查一张表上是否有物化视图
因为query是long类型的字段,所以不能用以下方法来检查
select * from all_mviews wherelower(to_lob(query)) like '%scott.emp_ori%'
采用以下方法
create table mv_info
(
owner varchar2(32),
mview_name varchar2(30),
query clob
)
insert into mv_info
select owner,mview_name,to_lob(query) from all_mviews
select * from mv_info where lower(query)like '%scott.emp_ori%'
疑问 这个选项如何能够影响到源表的行为
看看这个物化视图的完整脚本
CREATE MATERIALIZED VIEW "CENO"."MV_EMP"
ORGANIZATION HEAP
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
BUILD IMMEDIATE
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
REFRESH FORCE ON COMMIT
WITH PRIMARY KEY
USING DEFAULT LOCAL ROLLBACK SEGMENT
USING ENFORCED CONSTRAINTS ENABLE QUERY REWRITE
ASselect empno, deptno,sal
from scott.emp_ori
隐藏在MV之后的一些问题
SQL> desc MV_EMP
Name Type Nullable DefaultComments
------ ----------- -------- ---------------
EMPNO NUMBER(4)
DEPTNO NUMBER(2) Y
SAL NUMBER(7,2) Y
现在我们改变表名
conn scott/tiger@gq
rename emp_ori to emp_ori1
再查看MV_EMP的脚本,发现依然还是使用emp_ori表,这和依赖于emp_ori其它的对象不一样。
explain plan for
select * from mv_emp where empno=7369
select * from table(dbms_xplan.display())
---------------------------------------------------------------------------------------------
| Id |Operation |Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------
| 0 | SELECTSTATEMENT | | 1 | 39 | 1 (0)| 00:00:01|
| 1 | MAT_VIEW ACCESS BY INDEX ROWID| MV_EMP | 1 | 39 | 1 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | PK_EMP_ORI | 1 | | 1 (0)| 00:00:01|
---------------------------------------------------------------------------------------------
selectdbms_metadata.get_ddl('INDEX','PK_EMP_ORI') from dual
CREATE UNIQUE INDEX "CENO"."PK_EMP_ORI" ON"CENO"."MV_EMP" ("EMPNO")
PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
TABLESPACE "USERS"
我们并没有在MV_EMP的empno上建立唯一性索引,它是建立MV的时候自动建立上的。
修改原表的名称
rename emp_ori to emp_ori1
create table emp_ori as
select * from emp_ori1
select * from emp_ori
insert into emp_ori values(1000,20,12)
commit;
没有看到mv_emp变化
alter table scott.emp_ori add constraint pk_emp_ori1primary key (empno) ;
insert into emp_ori values(2000,20,12);
commit;
没有看到mv_emp变化
重新建立mv_emp后,才会看到mv有了刷新机制
select * from user_mviews
rename emp_ori to emp_ori2
rename emp_ori1 to emp_ori
insert into emp_ori values(2000,20,12);
commit;
也没有看到MV_emp的变化
修改表名城前后
观察select *from user_mview
OWNER |
CENO |
CENO |
MVIEW_NAME |
MV_EMP |
MV_EMP |
CONTAINER_NAME |
MV_EMP |
MV_EMP |
QUERY |
<Long> |
<Long> |
QUERY_LEN |
44 |
44 |
UPDATABLE |
N |
N |
UPDATE_LOG |
||
MASTER_ROLLBACK_SEG |
||
MASTER_LINK |
||
REWRITE_ENABLED |
Y |
Y |
REWRITE_CAPABILITY |
GENERAL |
GENERAL |
REFRESH_MODE |
COMMIT |
COMMIT |
REFRESH_METHOD |
FORCE |
FORCE |
BUILD_MODE |
IMMEDIATE |
IMMEDIATE |
FAST_REFRESHABLE |
DML |
DML |
LAST_REFRESH_TYPE |
COMPLETE |
COMPLETE |
LAST_REFRESH_DATE |
2009-1-8 21:41 |
2009-1-8 21:41 |
STALENESS |
FRESH |
COMPILATION_ERROR |
AFTER_FAST_REFRESH |
NA |
NA |
UNKNOWN_PREBUILT |
N |
N |
UNKNOWN_PLSQL_FUNC |
N |
N |
UNKNOWN_EXTERNAL_TABLE |
N |
N |
UNKNOWN_CONSIDER_FRESH |
N |
N |
UNKNOWN_IMPORT |
N |
N |
UNKNOWN_TRUSTED_FD |
N |
N |
COMPILE_STATE |
VALID |
COMPILATION_ERROR |
USE_NO_INDEX |
N |
N |
STALE_SINCE |
||
NUM_PCT_TABLES |
0 |
0 |
NUM_FRESH_PCT_REGIONS |
||
NUM_STALE_PCT_REGIONS |
create materialized view ceno.mv_sum_emp
build immediate
refresh on commit
enable query rewrite
as
select deptno,sum(sal) sal
from scott.emp_ori
group by deptno
explain plan for
select deptno,sum(sal) sal
from scott.emp_ori
group by deptno
select * from table(dbms_xplan.display())
-------------------------------------------------------------------------------------------
| Id |Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECTSTATEMENT | | 2| 52 | 3 (0)| 00:00:01 |
| 1 | MAT_VIEW REWRITEACCESS FULL| MV_SUM_EMP | 2 | 52 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
explain plan for
select /*+norewrite*/deptno,sum(sal)sal
from scott.emp_ori
group by deptno
select * from table(dbms_xplan.display())
------------------------------------------------------------------------------
| Id |Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECTSTATEMENT | | 2 | 14 | 4 (25)| 00:00:01 |
| 1 | HASH GROUP BY | | 2 | 14 | 4 (25)| 00:00:01 |
| 2| TABLE ACCESS FULL| EMP_ORI | 5 | 35 | 3 (0)| 00:00:01|
------------------------------------------------------------------------------
为什么说 查询重写技术比累积表要强大很多?
select deptno,sum(sal) sal
from scott.emp_ori
group by deptno
DEPTNO |
SAL |
30 |
2850 |
20 |
3787 |
insert into scott.emp_ori
select empno+1000, deptno,sal from scott.emp_ori
select deptno,sum(sal) sal
from scott.emp_ori
group by deptno
DEPTNO |
SAL |
30 |
5700 |
20 |
7574 |
explain plan for
select deptno,sum(sal) sal
from scott.emp_ori
group by deptno
select * from table(dbms_xplan.display())
-------------------------------------------------------------------------------------------
| Id |Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------------------
| 0 | SELECTSTATEMENT | | 2 | 52 | 3 (0)| 00:00:01|
| 1 | MAT_VIEW REWRITE ACCESS FULL| MV_SUM_EMP| 2 | 52 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
update MV_SUM_EMP set sal=sal+100
ORA-01732: 此视图的数据操纵操作非法
以上流程很好地建立数据复制,但是有以下一些问题
1、 如果不需要同步更新(原因)
2、 分区表建立主键很不方便
3、 不是每一张表都可以建立主键的
4、如果只关心部分数据变化
为了解决以上问题,oracle提供了mv_log
CREATE TABLE emp_hash_p
(
empno number(4),
deptno number(4),
sal number(16,2)
)
PARTITION BY HASH (empno) partitions 4
drop materialized view ceno.mv_emp
create materialized view mv_p_emp
build immediate
refresh on commit
enable query rewrite
as
select empno, deptno,sal
from emp_hash_p
原创文章,如果转载,请标注作者:田文 CSDN地址:http://blog.csdn.net/tiwen818