.Net程序员学用Oracle系列(23):视图理论、物化视图
我曾遇到一个项目的数据库中视图比表还要多很多(表和视图加起来上千个),几乎每个表都有对应的视图,而且有很多视图长得相似,比如有些视图关联的表一样,只是查询列表多或少了一两个字段。我敢断定,这就是因为一些水平低劣的开发人员看现有表或视图的数据不完全符合他的需要,就不假思索的拷贝过来改一下然后创建一个新的视图完事儿,久而久之,自然会出现很多相似甚至相同的视图。
在接手上述项目后,真正令我感到崩溃的是,查询语句往往涉及多个视图,且常常是相似的视图定义中又引用了另一个相似的视图,被引用的视图中又引用了另一个相似的视图……。总之就一个字——乱!有时候为了找与页面上字段对应的数据库字段得看完一堆的视图定义才能找到,因此那段时间我特别厌恶视图!并暗下决心:日后如果我能做主,绝不用视图。
后来我换了公司,新接触的项目数据库中基本没用视图。结果没过多久,我便发现代码中有很多相似甚至重复的查询语句,而且代码中的查询语句改起来也比较费劲,于是乎我对视图的主观意识发生了摇摆。我开始问自己:到底该不该用视图?如果用,要怎么用才合理?用了视图到底会降低性能还是会提升性能?
最后我通过阅读《Oracle Database Concepts》并反复实践和揣摩,终于对视图有所感悟。多学一点知识就少一点困惑,而我正是对视图理论方面有了大致了解后才解开对视图的各种困惑。本文第 1 节大部分内容是对官方手册的简化翻译,也夹杂了一些我个人的体会,英语好的读者也可以忽略本节直接阅读原文。
1、视图理论
视图是对一或多个表或其他视图中包含的数据的自定义呈现。视图将查询的输出视为一个表,因此可以认为视图就是存储的查询或虚拟表。视图中包含行和列,就像一个真实的表,但不包含数据本身。视图所引用的表被称为基表,视图总是呈现基表中最近的数据,视图可支持更新数据,所有对视图数据的更新都将被反映到视图的基表中,并受到基表的完整性约束和触发器的约束。
1.1、视图的存储
与表不同,视图不需要分配存储空间,视图也不包含实际数据。视图由查询定义,该查询从视图基表中提取或导出数据。因为视图是基于其他对象的,所以视图只需要在数据字典中存储定义视图的查询,而不需要额外的存储空间。
1.2、视图的作用
可通过视图以不同的形式来显示基表中的数据,而视图的强大之处在于它能够根据不同的用户需求来对基表中的数据进行不同形式的整合。视图的常见用途如下:
- 1、通过限制对基表中一组指定行或列的访问,来提供额外的安全控制。
- 2、视图允许通过表连接整合多个表中的相关行或列,构成一个新的数据集,从而达到隐藏数据复杂性的目的。
- 3、视图提供了从多个表中查询数据,而不必知道如何关联这些表的可能,因而简化了查询的 SQL 语句。
- 4、重命名视图的列或更改数据形式,不会影响视图所引用的基表,这样一来就能以不同的角度来呈现基表中的数据了。
- 5、保存复杂的查询,一个查询可能会对表数据进行复杂的计算,如果将这个查询保存为视图,那之后需求进行计算只需查询该视图即可。
- 6、表达不使用视图无法表达的查询,有时候用户需求过于复杂,几乎写不出来仅从基表中查询数据的单条 SQL 语句,如某些复杂的分组查询、联合查询等。
简单来说,合理运用视图,不仅可以提高数据的安全性,还可以少写代码,提升开发效率和程序的可维护性,也有利于在某些情况下灵活高效的控制数据的展现形式。
1.3、视图的工作机制
Oracle 将定义视图的语句以文本的形式存储在数据字典中。当用户在 SQL 语句中引用了视图时,Oracle 将完成以下三步动作:
- 1、将引用了视图的语句与视图的定义语句合并成一个语句。
- 2、在共享 SQL 区解析整合后的语句。
- 3、执行该语句。
如果共享 SQL 区中存在相似语句,Oracle 就不会重复解析,只有在共享 SQL 区中没有相似语句时,Oracle 才会为该语句创建新的共享 SQL 区。因此引用了视图的 SQL 语句也可能会节约内存进而提高查询性能。
1.4、视图的依赖性
定义视图的查询必须要引用其它对象(表、视图),换而言之,视图依赖于其所引用的对象而存在。Oracle 会自动地处理视图的依赖关系。例如,当用户删除视图的某个基表后再次创建它,Oracle 就会自动的去检查新的基表是否符合现有的视图定义,进而判断视图的有效性。在 PL/SQL Developer 中,所有 Oracle 认为无效的视图都会被打上红叉叉。
1.5、可更新的连接视图
连接视图是指在视图定义的查询的 FROM 字句中引用了多个表或视图的视图,而可更新的连接视图是指能够支持 UPDATE、INSERT 和 DELETE 操作的连接视图。数据字典视图ALL_UPDATABLE_COLUMNS、DBA_UPDATABLE_COLUMNS和USER_UPDATABLE_COLUMNS中包含了那些可更新的视图列信息。如果要确保视图可更新,那么视图定义中就不能包含以下语法结构:
- 1、集合运算符。
- 2、DISTINCT 运算符。
- 3、聚合函数或分析函数。
- 4、GROUP BY、ORDER BY、CONNECT BY 或 START WITH 子句。
- 5、SELECT 列表中的集合表达式。
- 6、SELECT 列表中的子查询。
- 7、JOIN 连接(也有例外情况)。
如果视图只引用了一个表,且包含该表的主键,一般就可以对视图进行 DML 操作。对于不支持 DML 操作的视图,如包含上述语法结构的连接视图,还可以使用 INSTEAD OF 触发器来更新数据,INSTEAD OF 触发器也被译作替代触发器。
语法:
CREATE [OR REPLACE] TRIGGER trigger_name
INSTEAD OF
{INSERT | DELETE | UPDATE [OF column1 [,column2 ...]]}
ON [SCHEMA.]view_name
[FOR EACH ROW] -- 因为 INSTEAD OF 触发器只能在行级上触发,所以没有必要指定
[WHEN condition]
[DECLARE]
-- 声明变量
BEGIN
-- 触发器代码
END;
示例:
CREATE OR REPLACE TRIGGER trg_staff
INSTEAD OF INSERT OR UPDATE OR DELETE ON demo.v_staff
BEGIN
IF INSERTING OR UPDATING THEN -- 不允许通过 v_staff 视图添加或修改数据
RAISE_APPLICATION_ERROR(-20000,'禁止通过 v_staff 视图添加或修改数据!');
END IF;
IF DELETING THEN -- 当接收到删除 v_staff 视图数据的指令时,删除对应数据
DELETE FROM demo.t_staff t WHERE t.staff_name=:OLD.staff_name;
END IF;
END;
1.6、内联视图
内联视图不是模式对象,而是一个有别名的子查询,一般定义在 FROM 字句之后,可以在 SQL 语句中像使用普通视图一样的使用。内联视图是一种临时视图,不会存储到数据字典中,它和标准视图的主要区别是:不需要在执行 SQL 语句之前进行解析和创建共享 SQL 区。
2、物化视图
物化视图是包含查询结果的数据库对象,用于汇总、计算、复制及分发数据。物化视图能够预先计算并保存表连接或聚集等耗时较多的操作结果,这样,在执行查询时,就可以避免进行这些耗时的操作,从而快速的得到结果。物化视图是一种特殊的物理表,“物化”视图是相对普通视图而言的。普通视图是虚拟表,应用的局限性大,任何对视图的查询,Oracle 都实际上转换为视图 SQL 语句的查询,这样对整体查询性能的提高,并没有实质上的好处。
2.1、刷新物化视图
Oracle 在对主表进行 DML 操作之后,会通过刷新来维护物化视图中的数据(以确保物化视图和基表中的数据同步)。刷新模式有两种:ON DEMAND 和 ON COMMIT,而刷新方式有四种:FAST、COMPLETE、FORCE 和 NEVER。FAST 刷新采用增量刷新,只刷新自上次刷新以后进行的修改。COMPLETE 刷新对整个物化视图进行完全的刷新。如果选择FORCE 方式,Oracle 会在刷新前先判断下是否可以进行快速刷新,如果可以则采用 FAST 刷新,否则采用 COMPLETE 刷新。NEVER 指物化视图不进行任何刷新。
对于使用快速刷新方法的物化视图,物化视图日志或直接加载日志将保留对主表的更改记录。已经创建好的物化视图也还可以再修改它的刷新方式。物化视图还可以按要求定期刷新。
2.2、物化视图日志
物化视图日志是将更改同步到主表的模式对象。通过物化视图日志可以逐级刷新主表上定义的物化视图,此过程被称为增量或快速刷新。如果没有物化视图日志,Oracle 必须重新执行物化视图查询来刷新物化视图,这个过程称为完全刷新。通常,快速刷新比完全刷新需要更少的时间。
物化视图日志位于和主表相同模式中的主数据库中。每个主表上最多能定义一个物化视图日志。Oracle 可以根据物化视图日志对所有需要快速刷新的物化视图执行快速刷新。要快速刷新物化连接视图,必须为实例化视图引用的每个表创建一个物化视图日志。
创建物化视图日志:
示例一(创建支持主键实例化视图快速刷新的物化视图日志,并指定物理和存储特性):
CREATE MATERIALIZED VIEW LOG ON demo.t_staff
PCTFREE 5 -- 块保留的空间百分比
TABLESPACE users
STORAGE (INITIAL 10K NEXT 10K);
示例二(创建支持快速刷新 ROWID 物化视图和物化连接视图的物化视图日志):
CREATE MATERIALIZED VIEW LOG ON demo.t_staff WITH PRIMARY KEY,ROWID;
示例三(创建支持快速刷新物化聚合视图的物化视图日志):
CREATE MATERIALIZED VIEW LOG ON demo.t_staff
WITH ROWID, SEQUENCE(staff_id)
INCLUDING NEW VALUES;
更多创建物化视图日志的细节请参考:《Oracle Database SQL Reference: CREATE MATERIALIZED VIEW LOG》。修改物化视图日志的细节请参考:《Oracle Database SQL Reference: ALTER MATERIALIZED VIEW LOG》。
删除物化视图日志:语法结构和删除表相似,详细请参考《Oracle Database SQL Reference: DROP MATERIALIZED VIEW》。
DROP MATERIALIZED VIEW LOG ON demo.t_staff;
2.3、管理物化视图
创建物化视图:
语法:
CREATE MATERIALIZED VIEW
[ schema. ]materialized_view
[ column_alias [, column_alias]... ]
[ OF [ schema. ]object_type ]
[ (scoped_table_ref_constraint) ]
{ ON PREBUILT TABLE
[ { WITH | WITHOUT } REDUCED PRECISION ]
| physical_properties materialized_view_props
}
[ USING INDEX
[ physical_attributes_clause
| TABLESPACE tablespace
]
[ physical_attributes_clause
| TABLESPACE tablespace
]...
| USING NO INDEX
]
[ create_mv_refresh ]
[ FOR UPDATE ]
[ { DISABLE | ENABLE }
QUERY REWRITE
]
AS subquery ;
示例一:
CREATE MATERIALIZED VIEW LOG ON demo.t_staff
WITH PRIMARY KEY
INCLUDING NEW VALUES;
CREATE MATERIALIZED VIEW mv_staff
BUILD IMMEDIATE
REFRESH FAST ON COMMIT
AS SELECT t1.staff_id,t1.staff_name,DECODE(t1.gender,1,'男',0,'女','未知') gender
FROM demo.t_staff t1
WHERE t1.is_disabled=0;
示例二:
CREATE MATERIALIZED VIEW mv_staff2
AS SELECT t1.staff_id,t1.staff_name,DECODE(t1.gender,1,'男',0,'女','未知') gender,
EXTRACT(YEAR FROM SYSDATE)-EXTRACT(YEAR FROM t1.birthday) age
FROM demo.t_staff t1
WHERE t1.is_disabled=0;
更多创建物化视图的细节请参考:《Oracle Database SQL Reference: CREATE MATERIALIZED VIEW》。修改物化视图的细节请参考:《Oracle Database SQL Reference: ALTER MATERIALIZED VIEW》。
删除物化视图:语法结构和删除表相似,详细请参考《Oracle Database SQL Reference: DROP MATERIALIZED VIEW》。
DROP MATERIALIZED VIEW mv_staff2;
2.4、物化视图与索引
物化视图和索引都是为提高数据库性能而存在的,所以它们有一定的相似之处。列举如下:
- 1、它们都消耗存储空间。
- 2、当主表中的数据发生更改时,都需要刷新。
- 3、当它们用于查询时,都可以提高 SQL 执行的性能。
- 4、它们的存在对 SQL 应用程序和用户是透明的(能看到且可以直接操作的意思)。
- 5、可以对它们进行分区。
物化视图与索引不同点之一是:物化视图可以在 SQL 语句中直接访问,而索引是否生效取决于 Oracle 系统。
3、总结
本文主要讲述了普通视图的基本原理和物化视图基本用法,希望能对读者有所帮助。另外,由于我本人物化视图用的也不多,所以讲述的比较片面和浅显,需要进一步了解的读者可以再看看官网手册:《Oracle Database Concepts: Overview of Materialized Views》。
本文链接:http://www.cnblogs.com/hanzongze/p/oracle-view.html
版权声明:本文为博客园博主 韩宗泽 原创,作者保留署名权!欢迎通过转载、演绎或其它传播方式来使用本文,但必须在明显位置给出作者署名和本文链接!本人初写博客,水平有限,若有不当之处,敬请批评指正,谢谢!
.Net程序员学用Oracle系列(23):视图理论、物化视图的更多相关文章
- .Net程序员学用Oracle系列(25):触发器详解
1.触发器理论 1.1.触发器的应用场景 1.2.触发器的类型 1.3.DML 触发器的触发顺序 2.触发器实战 2.1.创建触发器 2.1.1.创建 DML 触发器 2.1.2.创建 DDL 触发器 ...
- .Net程序员学用Oracle系列(7):视图、函数、存储过程、包
1.视图 1.1.创建.删除及调用普通视图 1.2.高级视图介绍 2.函数 2.1.系统函数介绍 2.2.创建.删除及调用自定义函数 3.存储过程 3.1.创建.修改及删除存储过程 3.2.调用存储过 ...
- .Net程序员学用Oracle系列(9):系统函数(上)
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.字符函数 1.1.字符函数简介 1.2.语法说明及案例 2.数字函数 2.1.数字函数简介 2.2.语法说明及案例 3.日期 ...
- .Net程序员学用Oracle系列(10):系统函数(下)
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.转换函数 1.1.TO_CHAR 1.2.TO_NUMBER 1.3.TO_DATE 1.4.CAST 2.近似值函数 2. ...
- .Net程序员学用Oracle系列(1):导航目录
本人从事基于 Oracle 的 .Net 企业级开发近三年,在此之前学习和使用的都是 (MS)SQL Server.未曾系统的了解过 Oracle,所以长时间感到各种不习惯.不方便.怪异和不解,常会遇 ...
- .Net程序员学用Oracle系列(2):准备测试环境
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.创建说明 1.1.为什么要创建的测试环境? 1.2.了解 Oracle 实例的默认用户 2.创建环境 2.1.创建基本环境 ...
- .Net程序员学用Oracle系列(6):表、字段、注释、约束、索引
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.表 1.1.创建表 1.2.修改表 & 删除表 2.字段 2.1.添加字段 2.2.修改字段 & 删除字段 ...
- .Net程序员学用Oracle系列(7):视图、函数、过程、包
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.视图 1.1.创建视图 2.函数 2.1.创建函数 2.2.调用函数 3.过程 3.1.创建过程 3.2.调用过程 4.包 ...
- .Net程序员学用Oracle系列(8):触发器、任务、序列、连接
<.Net程序员学用Oracle系列:导航目录> 本文大纲 1.触发器 1.1.创建触发器 1.2.禁用触发器 & 启用触发器 & 删除触发器 2.任务 2.1.DBMS_ ...
随机推荐
- SLF4J 的几种实际应用模式--之三:JCL-Over-SLF4J+SLF4J
我们前面已经讲过了 SLF4J 的两种用法:SLF4J+Log4J 和 SLF4J+Logback,那是在比较理想的情况下,所用组件只使用了 SLF4J 这一种统一日志框架的时候.可是 JCL 一直 ...
- Frame框架
框架 frameset 框架集 如果使用框架集,当前页面不能有body cols="300,*" :左右拆分,左边宽300,右边宽剩余 rows=" ...
- Java变量和对象的作用域
大多数程序设计语言都提供了"作用域"(Scope)的概念. 对于在作用域里定义的名字,作用域同时决定了它的"可见性"以及"存在时间".在C, ...
- TypeScript入门-基本数据类型
▓▓▓▓▓▓ 大致介绍 TypeScript是由C#语言之父Anders Hejlsberg主导开发的一门编程语言,TypeScript本质上是向JavaScript语言添加了可选的静态类型和基于类的 ...
- python服务器环境搭建(3)——参数配置
前面我们已安装好了python服务器运行所需要的相关软件,而最重要最繁琐的就是参数配置,写这篇就踩了好多坑,花了好多时间,遇到了各种各样的问题.好了费话少说,直接进入本篇话题. PS:本人不是专业的运 ...
- JIRA6.36-7.23数据迁移文档
JIRA6.3.6-JIRA7.2.3数据迁移文档 安装JIRA7.2.3 安装包位于服务器/opt/SOFTWARE_PACKAGE目录下 建立JIRA安装的目录数据目录 cd /opt mkdir ...
- html中引入调用另一个html的方法
html中引入调用另一个html的方法,尝试了好几种,都列出来: 其中第一种是最好的,其他的方法,可以尝试看看,是不是适合你当前项目 一.div+$("#page1").load( ...
- 老李分享:pep8 python代码规范
老李分享:pep8 python代码规范 什么是PEPPEP是 Python Enhancement Proposal 的缩写,翻译过来就是 Python增强建议书 . PEP8 译者:本文基于 20 ...
- lumen 中的 .env 配置文件简介和适用场景
lumen 是 laravel 的衍生品,核心功能的使用和 laravel 都是一致的,但配置文件这一方面,lumen 在 laravel 的基础上增加了更简便的配置方式: lumen 采用了 Dot ...
- IC卡读卡器web开发,支持IE,Chrome,Firefox,Safari,Opera等主流浏览 器
IC卡读卡器在web端的应用越来越多,但是早期发布的ocx技术只支持IE浏览器,使用受到了很多的限制.IC卡读卡器云服务的推 出,彻底解决了以上的局限,使得IC卡读卡器不仅可以应用在IE浏览器上,还可 ...