二、物化视图
2.1什么是物化视图
视图是一张虚拟的表,他并不是真实存在,他只是一个sql语句,物化视图是一张真实存在的表,区别在于,物化视图是要建立副本的,它是把数据查出来放到一个副本里。物化视图更像一张表。视图他只是一个查询,她不需要建立副本。物化视图查询效率更高,但是占用存储空间。
物化视图相当于查询单表,不需要关联。视图相当于多表关联,需要关联查询。物化视图就是提高查询效率,但是占用存储空间。
视图是一个虚拟表(也可以认为是一条语句),基于它创建时指定的查询语
句返回的结果集。每次访问它都会导致这个查询语句被执行一次。为了避免每次
访问都执行这个查询,可以将这个查询结果集存储到一个物化视图(也叫实体化
视图)。
物化视图与普通的视图相比的区别是物化视图是建立的副本,它类似于一张
表,需要占用存储空间。而对一个物化视图查询的执行效率与查询一个表是一样
的。
2.2创建物化视图语法
CREATE METERIALIZED VIEW
view_name
[BUILD IMMEDIATE | BUILD DEFERRED ]
REFRESH [FAST|COMPLETE|FORCE]
[
ON [COMMIT |DEMAND ] | START WITH (start_time) NEXT
(next_time)
]
AS
subquery(查询语句的意思)
BUILD IMMEDIATE(立即创建)
是在创建物化视图的时候就生成数据
BUILD DEFERRED (延迟创建)
则在创建时不生成数据,以后根据需要再生成数据。
默认为
BUILD IMMEDIATE
。
刷新(
REFRESH
):指当基表发生了
DML
操作后,物化视图何时采用哪种
方式和基表进行同步。
REFRESH 后跟着指定的刷新方法有三种:FAST、COMPLETE、FORCE
。
FAST
刷新采用增量刷新,只刷新自上次刷新以后进行的修改。
COMPLETE
刷新对整
个物化视图进行完全的刷新。如果选择
FORCE
方式,则
Oracle
在刷新时会去判
断是否可以进行快速刷新,如果可以则采用
FAST
方式,否则采用
COMPLETE
的方式。
FORCE
是默认的方式。
刷新的模式有两种:
ON DEMAND
和
ON COMMIT
。
ON DEMAND
指需要
手动刷新物化视图(默认)。
ON COMMIT
指在基表发生
COMMIT
操作时自动
刷新。
2.3案例
1.创建手动刷新的物化视图
手动刷新就是你提交基表的时候他不会立刻更新数据,手动刷新物化视图就是不加选项,on demand 默认参数可以不写的。
需求:查询地址
ID,
地址名称和所属区域名称
,
结果如下:
语句:
create materialized view
mv_address
as
select
ad.id,ad.name adname,ar.name ar_name
from
t_address ad,t_area ar
where
ad.areaid=ar.id
执行上边的语句后查询
select
*
from
mv_address;
查询结果如下:
基表:就是你的物化视图来自于哪张表,这个表就是基表。
这时,我们向地址表(
T_ADDRESS
)中插入一条新记录,
insert into
t_address
values
(
8
,
'
宏福苑小区
'
,
1
,
1
);
再次执行上边的语句进行查询,会发现新插入的语句并没有出现在物化视图中。
我们需要通过下面的语句(
PL/SQL
),手动刷新物化视图:
begin
DBMS_MVIEW.refresh(
'MV_ADDRESS'
,
'C'
);
end
;
或者通过下面的命令手动刷新物化视图:
EXEC DBMS_MVIEW.refresh('MV_ADDRESS','C');
注意:此语句需要在命令窗口中执行(新建--》选择command window选项)。
执行此命令后再次查询物化视图,就可以查询到最新的数据了。
DBMS_MVIEW.refresh
实际上是系统内置的存储过程,关于存储过程我们在第
4
章会详细讲解。
2.创建自动刷新的物化视图,和上例一样的结果集
自动刷新的物化视图就是加上refresh on commit关键字,就是让你的基表发生变更的时候,去自动的刷新物化视图。
语句如下:
create materialized view
mv_address2
refresh
on commit
as
select
ad.id,ad.name adname,ar.name ar_name
from
t_address ad,t_area ar
where
ad.areaid=ar.id
创建此物化视图后,当
T_ADDRESS
表发生变化时,
MV_ADDRESS2
自动跟着
改变。
查询结果:
3.创建时不生成数据的物化视图
create materialized view
mv_address3
build deferred
refresh
on commit
as
select
ad.id,ad.name adname,ar.name ar_name
from
t_address ad,t_area ar
where
ad.areaid=ar.id;
创建后执行下列语句查询物化视图
select
*
from
mv_address3
查询结果:
执行下列语句生成数据
begin
DBMS_MVIEW.refresh(
'MV_ADDRESS3'
,
'C'
);
end
;
再次查询,得到结果:
由于我们创建时指定的
on commit ,
所以在修改数据后能立刻看到最新数据,无须
再次执行
refresh
4.创建增量刷新的物化视图
增量刷新就是加上refresh fast的关键字,
如果创建增量刷新的物化视图,必须首先创建物化视图日志
create materialized view log on
t_address
with rowid
;
create materialized view log on
t_area
with rowid
创建的物化视图日志名称为
MLOG$_
表名称
创建物化视图
create materialized view
mv_address4
refresh fast
as
select
ad.rowid adrowid ,ar.rowid arrowid, ad.id,ad.name
adname,ar.name ar_name
from
t_address ad,t_area ar
where
ad.areaid=ar.id;
注意:创建增量刷新的物化视图,必须:
1. 创建物化视图中涉及表的物化视图日志。
2. 在查询语句中,必须包含所有表的 rowid ( 以 rowid 方式建立物化视图日志 )
当我们向地址表插入数据后,物化视图日志的内容:
SNAPTIME$$
:用于表示刷新时间。
DMLTYPE$$
:用于表示
DML
操作类型,
I
表示
INSERT
,
D
表示
DELETE
,
U表示 UPDATE
。
OLD_NEW$$
:用于表示这个值是新值还是旧值。
N
(
EW
)表示新值,
O
(
LD
)
表示旧值,
U
表示
UPDATE
操作。
CHANGE_VECTOR$$
:表示修改矢量,用来表示被修改的是哪个或哪几个字段。
此列是
RAW
类型,其实
Oracle
采用的方式就是用每个
BIT
位去映射一个列。
插入操作显示为:
FE,
删除显示为:
OO
更新操作则根据更新字段的位置而显示
不同的值。
当我们手动刷新物化视图后,物化视图日志被清空,物化视图更新。
begin
DBMS_MVIEW.refresh(
'MV_ADDRESS4'
,
'C'
);
end
;
三、序列--用的多的是创建简单序列,和序列的2个伪列
3.1什么是序列
序列是 ORACLE 提供的用于产生一系列唯一数字的数据库对象。
序列是产生连续数字的数据库对象。我们插入语句的时候,第一个值是主键值,主键值是直接写死的,在mysql当中有一个自动增长的特性,自动增长的话这个值就不需要指定了。oracle没有提供表中的字段有自动增长的特性,但是他提供了序列,序列是独立于表的数据库对象。序列是专门产生这些数字的,表可以使用这些数字。
3.2创建与使用简单序列
我们知道表有2个伪列,rowid,rownum,序列也有2个伪列,nextavl(下一个值)和currval(当前值)。
创建序列语法:
create sequence 序列名称
通过序列的伪列来访问序列的值
NEXTVAL 返回序列的下一个值---就是下一个值
CURRVAL 返回序列的当前值----就是当前值
注意:我们在刚建立序列后,无法提取当前值,只有先提取下一个值时才能再次
提取当前值。
提取下一个值
select 序列名称.nextval from dual
提取当前值
select 序列名称.currval from dual
查询结果:
oracle每执行一次序列自动往下走,先是1,在执行一次就是2,再执行一次是3,以此类推。。
3.3创建复杂序列
有时候我们产生的序列不是连续的值,比如第一次查出来是1,第二次是3,第三次是5,每次增长是2.也就是偶数和奇数这样的。
语法:
CREATE SEQUENCE
sequence
//
创建序列名称
[INCREMENT BY
n
] //
递增的序列值是
n
如果
n
是正数就递增
,
如果是负数就递减 默
认是
1
[START WITH
n
] //
开始的值
,
递增默认是
minvalue
递减是
maxvalue
[{MAXVALUE
n
| NOMAXVALUE}] //
最大值--单个方向
[{MINVALUE
n
| NOMINVALUE}] //最小值--单个方向
[{CYCLE | NOCYCLE}] //
循环
/
不循环---绕圈
[{CACHE
n
| NOCACHE}];//
分配并存入到内存中
cycle循环就是周而复始。
cache的意思就是缓存(就是内存),序列是存储在磁盘上的,缓存就是吧这个值放到内存当中,下次再去访问从缓存中取值。
3.4案例
1. 有最大值的非循环序列
创建序列的语句:
create sequence
seq_test1
increment by
10
//每次增长10
start with
10
//从10开始
maxvalue
300
minvalue
20
意思:从10开始,每次增长10个,最大值是300,最小值是20,到了最大值300的话,在执行的话就会报错了。
以上的错误,是由于我们的开始值小于最小值 。开始值不能小于最小值,修改
以上语句:
create sequence
seq_test1
increment by
10
start with
10
maxvalue
300
minvalue
5
我们执行下列语句提取序列值,当序列值为
300
(最大值)的时候再次提取值,
系统会报异常信息。
2. 有最大值的循环序列---类似于for循环,循环默认是20,也可以自己设定
create sequence
seq_test2
increment by
10
start with
10
maxvalue
300
minvalue
5
cycle
;
当序列当前值为
300
(最大值),再次提取序列的值
select
seq_test2.nextval
from
dual
提取的值为:
由此我们得出结论,循环的序列,第一次循环是从开始值开始循环,而第二次循
环是从最小值开始循环。
思考问题:
下列语句是否会报错?为什么?
create sequence
seq_test3
increment by
10
start with
10
minvalue
5
cycle
;
答:此为错误的语句。因为你创建的是一个循环的序列,所以必须指定最大值,
否则会报错。
3. 带缓存的序列
我们执行下列语句:
create sequence
seq_test3
increment by
10
start with
10
maxvalue
300
minvalue
5
cycle
cache
50
;
我们执行上边语句的意思是每次取出
50
个缓存值,但是执行会提示错误
上边错误提示的意思是:缓存设置的数必须小于每次循环的数。
我们缓存设定的值是
50
,而最大值是
300
,那么为什么还会提示这样的信息呢?
其实我们的
cache
虽然是
50
,但是我们每次增长值是
10
。这样
50
次缓存提取出
的数是
500
(
50*10
)
我们更改为下列的语句:
create sequence
seq_test4
increment by
10
start with
10
maxvalue
500
minvalue
10
cycle
cache
50
;
下列语句依然会提示上边的错误,这是因为还存在一个
minvalue
,
minvalue
和
maxvalue
之间是
490
个数,也就是一次循环可以提取
490
,但是我们的缓存是
500
。
我们再次修改语句:
create sequence
seq_test5
increment by
10
start with
10
maxvalue
500
minvalue
9
cycle
cache
50
;
把最小值减
1
,或把最大值加
1
,都可以通过。
每次缓存多少根据你设置的数字来,他只会缓存那几个数,相当于设置10,就缓存10、20、30.。。超过了这个设置的100就报错了,所以是100设置小了点。
3.5修改和删除序列
注意:起始参数不能修改,其他的参数都能改。
修改序列:使用
ALTER SEQUENCE
语句修改序列,不能更改序列的
START
WITH
参数
ALTER SEQUENCE 序列名称 MAXVALUE 5000 CYCLE;
删除序列:
DROP SEQUENCE 序列名称;
四、同义词
4.1什么是同义词--就是别名
同义词实质上是指定方案对象的一个别名。通过屏蔽对象的名称和所有者以
及对分布式数据库的远程对象提供位置透明性,同义词可以提供一定程度的安全
性。同时,同义词的易用性较好,降低了数据库用户的
SQL
语句复杂度。
同义词允许基对象重命名或者移动,这时,只需对同义词进行重定义,基于同义
词的应用程序可以继续运行而无需修改。
你可以创建公共同义词和私有同义词。其中,公共同义词属于
PUBLIC
特殊
用户组,数据库的所有用户都能访问;而私有同义词包含在特定用户的方案中,
只允许特定用户或者有基对象访问权限的用户进行访问。
同义词本身不涉及安全,当你赋予一个同义词对象权限时,你实质上是在给
同义词的基对象赋予权限,同义词只是基对象的一个别名。
4.2创建与使用同义词
创建同义词的具体语法是:
create [public] SYNONYM synooym for object;
其中
synonym
表示要创建的同义词的名称,
object
表示表,
视图
,序列等我们要
创建同义词的对象的名称。
你加上public就是共有同义词,不加上public就是私有同义词,就只能当前用户可用该别名。
4.3案例
1.
私有同义词
需求:为表
T_OWNERS
创建
(
私有
)
同义词 名称为
OWNERS
语句:
create synonym
OWNERS
for
T_OWNERS;
使用同义词:
select
*
from
OWNERS ;
查询结果如下:
2.
公有同义词
需求:为表
T_OWNERS
创建
(
公有
)
同义词 名称为
OWNERS2
:
create
public
synonym
OWNERS2
for
T_OWNERS;
以另外的用户登陆,也可以使用公有同义词:
select
*
from
OWNERS2 ;
查询结果如下:
五、索引
5.1什么是索引
索引就是一本书的目录,就是找东西快。你要查某条记录,你要加上where条件,它的原理就是把整个表扫描一遍,吧符合结果的挑选出来。也就是逐行扫描,找到你想要的结果。
上百万级别的时候在考虑索引。索引不是逐行扫描,而是通过索引找到这条记录的通过物理地址,它会吧这些数据整成索引的数据结构,索引就是一个树,通过树快速找到符合条件的物理地址,也就是rowid。
索引是用于加速数据存取的数据对象。合理的使用索引可以大大降低
i/o
次
数
,
从而提高数据访问性能。
索引是需要占据存储空间的,也可以理解为是一种特殊的数据。形式类似于
下图的一棵“树”,而树的节点存储的就是每条记录的物理地址,也就是我们提
到的伪列(
ROWID
)
5.2普通索引
语法:
create index
索引名称
on
表名
(
列名
);
需求:我们经常要根据业主名称搜索业主信息,所以我们基于业主表的
name
字
段来建立索引。语句如下:
create index
index_owners_name
on
T_OWNERS(
name
)
索引性能测试:
创建一个两个字段的表
create table
T_INDEXTEST (
ID NUMBER
,
NAME VARCHAR2
(
30
)
);
编写
PL/SQL
插入
100
万条记录(关于
PL/SQL
我们在第四章会学到)
BEGIN
FOR
i
in
1
..1000000
loop
INSERT INTO
T_INDEXTEST
VALUES
(i,
'AA'
||i);
end loop
;
commit
;
END
;
创建完数据后,根据
name
列创建索引
CREATE INDEX
INDEX_TESTINDEX
on
T_INDEXTEST(
name
)
执行下面两句
SQL
执行
SELECT
*
from
T_INDEXTEST
where ID
=
765432
;
SELECT
*
from
T_INDEXTEST
where NAME
=
'AA765432'
;
我们会发现根据
name
查询所用的时间会比根据
id
查询所用的时间要短
5.3唯一索引--加上unique关键字
如果我们需要在某个表某个列创建索引,而这列的值是不会重复的。这是我们可
以创建唯一索引。
语法:
create
unique
index
索引名称
on
表名
(
列名
);
需求:在业主表的水表编号一列创建唯一索引
语句:
create
unique
index
index_owners_watermeter
on
T_OWNERS(watermeter);
5.4复合索引
我们经常要对某几列进行查询,就要用复合索引。
我们经常要对某几列进行查询,比如,我们经常要根据学历和性别对学员进行搜
索,如果我们对这两列建立两个索引,因为要查两棵树,查询性能不一定高。那
如何建立索引呢?我们可以建立复合索引,也就是基于两个以上的列建立一个索
引 。
语法:
create index
索引名称
on
表名
(
列名
,
列名
.....);
根据地址和门牌号对学员表创建索引,语句如下:
create index
owners_index_ah
on
T_OWNERS(addressid,housenumber);
5.5反向键索引--加上reverse关键字
当某个字段的值为连续增长的值,就会建立反向键索引。反就是二进制反。
应用场景:当某个字段的值为连续增长的值,如果构建标准索引,会形成歪脖子
树。这样会增加查询的层数,性能会下降。建立反向键索引,可以使索引的值变
得不规则,从而使索引树能够均匀分布。
语法:
create index
索引名称
on
表名
(
列名
)
reverse
;
5.6位图索引--bitmap关键字
前面的索引都是BTtree*索引,位图就是一张图片。每一个rowid存在节点上,位图索引就是每一个rowid存在像素节点上。他们之间没有先后顺序的。位图索引只能用等于号,不能用大于号,小于号啥的。
范围、模糊查询都会造成索引失效。
使用场景:位图索引适合创建在低基数列上
位图索引不直接存储 ROWID,而是存储字节位到 ROWID 的映射
优点:减少响应时间,节省空间占用
语法:
create
bitmap
index
索引名称
on
表名
(
列名
);
需求:我们在
T_owners
表的
ownertypeid
列上建立位图索引,语句:
create bitmap index
index_owners_typeid
on
T_OWNERS(ownertypeid)