Oracle Read-only Tablespace(只读表空间)

一,只读表空间与数据的备份/恢复

表空间设置成只读之后,只需要执行一次备份操作即可,在后续备份时不再需要考虑这些表空间的备份。原因很容易理解,这些表空间中的数据已经不再改变,存储在表空间中的数据状态始终保持在表空间设置为Read-Only那一刻,Oracle也不需要对它们进行额外的恢复工作,比如应用归档。

我们创建两个表空间,一个是只读(Read-Only)的,一个是常规的(Read-Write),下面来比较这两个表空间数据文件的变化情况。

SQL> create tablespace readonly datafile '/u01/app/oracle/oradata/readonly01.dbf' size 10m;

Tablespace created.

SQL> create tablespace readwrite datafile '/u01/app/oracle/oradata/readwrite01.dbf' size 10m;

Tablespace created.

SQL> alter tablespace readonly read only;

Tablespace altered.

这样,我们就创建了两个表空间readonly和readwrite,并把表空间readonly的状态设置为只读。

SQL> select name,file#,checkpoint_change#,status,enabled from v$datafile where name like '%read%';

NAME                 FILE# CHECKPOINT_CHANGE# status enabled
--------------------------------------------- ---------- -------------
/u01/app/oracle/oradata/readonly01.dbf   6   4342263 ONLINE READ ONLY
/u01/app/oracle/oradata/readwrite01.dbf  7   4341997 ONLINE READ WRITE

我们先记录下当前状态下两个表空间数据文件的CHECKPOINT_CHANGE#号,这个号表示表空间数据文件在Oracle数据库运行时某个时间点的状态。CHECKPOINT_CHANGE#是Oracle里面的一个序号,用来标识一个先后顺序,通常用于保护数据块的完整性或者一致性的查询。当数据块做了修改,它的CHECKPOINT_CHANGE#值就会发生相应的改变。

SQL> alter system checkpoint;

System altered.

我们发出一个CHECKPOINT命令,这个命令实际上是将内存中的脏数据块写入到磁盘上的文件中,并更新文件头部信息,以保证数据块中数据的一致性。

SQL> select name,file#,checkpoint_change#,status,enabled from v$datafile where name like '%read%';

NAME                 FILE# CHECKPOINT_CHANGE# status enabled
--------------------------------------------- ---------- -------------
/u01/app/oracle/oradata/readonly01.dbf   6   4342263 ONLINE READ ONLY
/u01/app/oracle/oradata/readwrite01.dbf  7   4343696 ONLINE READ WRITE

我们看到,执行了CHECKPOINT命令之后,READWRITE表空间数据文件的checkpoint_change#号发生了变化,这说明这个表空间相比之前的状态,它的数据文件已经产生了变化。
尽管我们没有对这个表空间做任何操作,但不能保证Oracle不这样做(实际上,这里是表空间数据文件的文件头数据块产生了变化)。我们知道,只要数据文件的checkpoint_change#号发生了变化,Oracle就需要进行恢复;而这里,READONLY的checkpoint_change#号并没有变化,看起来就像静止在那里一样。
这就是说,如果此时Oracle数据库出现问题,比如DOWN掉了,在数据库重新OPEN时,READONLY表空间是不需要恢复的,因为它的状态依然保持在将它置于READ-ONLY那一刻,那一刻数据库是好的。
而READWRITE表空间就不同了,如果此时数据库DOWN掉了,它就需要进行恢复,因为这个表空间上的数据块状态是持续更新的,它需要通过联机日志(或者归档日志)将它恢复到最后Oracle数据库DOWN掉时的状态。
   
我们继续来看,现在将这两个表空间的状态改为离线。
SQL> alter tablespace readonly offline;

Tablespace altered.

SQL> alter tablespace readwrite offline;

Tablespace altered.

SQL> select name,file#,checkpoint_change#,status,enabled from v$datafile where name like '%read%';

NAME                 FILE# CHECKPOINT_CHANGE# status enabled
--------------------------------------------- ---------- -------------
/u01/app/oracle/oradata/readonly01.dbf   6  4342263 OFFLINE READ ONLY
/u01/app/oracle/oradata/readwrite01.dbf  7  4351566 OFFLINE READ WRITE

我们看到,READONLY表空间的checkpoint_change#号依然保持不变。

SQL> alter system checkpoint;

System altered.

SQL> select name,file#,checkpoint_change#,status,enabled from v$datafile where name like '%read%';

NAME                 FILE# CHECKPOINT_CHANGE# status enabled
--------------------------------------------- ---------- -------------
/u01/app/oracle/oradata/readonly01.dbf   6  4342263 OFFLINE READ ONLY
/u01/app/oracle/oradata/readwrite01.dbf  7  4351566 OFFLINE READ WRITE

当数据文件状态为离线时,不论之前它是只读还是读写表空间,它的状态都不再改变。

现在,我们把这两个表空间的状态重新改为在线。

SQL> alter tablespace readonly online;

Tablespace altered.

SQL> alter tablespace readwrite online;

Tablespace altered.

SQL> select name,file#,checkpoint_change#,status,enabled from v$datafile where name like '%read%';

NAME                 FILE# CHECKPOINT_CHANGE# status enabled
--------------------------------------------- ---------- -------------
/u01/app/oracle/oradata/readonly01.dbf   6  4342263 OFFLINE READ ONLY
/u01/app/oracle/oradata/readwrite01.dbf  7  4351660 OFFLINE READ WRITE

我们看到,READWRITE表空间的checkpoint_change#号再次改变了。实际上,在把READWRITE表空间的状态改为在线时,Oracle对它进行了恢复操作,使它的状态和数据库当前状态一致;而READONLY表空间依然静止不动地保持着它最初的状态,和数据库的变化毫无关系。
这样看来,在备份和恢复上,对只读表空间备份一次就够了;而对其他的读写表空间的备份,可能需要定期做全备份或者增量备份,同时还需要备份恢复时所需要的归档日志。这些备份集不但需要大量的磁盘空间,而且恢复时也可能会相当耗时。

二,只读表空间可以防止数据被意外删除和修改

----创建一个jack表空间----
SQL> create tablespace jack datafile '/u01/app/oracle/oradata/jack01.dbf' size 500m;

Tablespace created.

SQL> show user;
USER is "JACK"

----创建一张表jack----
SQL> create table jack tablespace jack as select * from dba_objects;

Table created.

----将表空间状态设置为只读----
SQL> alter tablespace jack read only;

Tablespace altered.

----做一些修改数据的操作,无法进行DELETE操作----
SQL> delete from jack;
delete from jack
            *
ERROR at line 1:
ORA-00372: file 6 cannot be modified at this time
ORA-01110: data file 6: '/u01/app/oracle/oradata/jack01.dbf'

----无法进行UPDATE操作----
SQL> update jack set object_id=object_id*10;
update jack set object_id=object_id*10
       *
ERROR at line 1:
ORA-00372: file 6 cannot be modified at this time
ORA-01110: data file 6: '/u01/app/oracle/oradata/jack01.dbf'

----无法进行INSERT操作,也就是说,对于只读表空间上的数据,无法进行DML操作。----
SQL> insert into jack select * from dba_objects;
insert into jack select * from dba_objects
            *
ERROR at line 1:
ORA-00372: file 6 cannot be modified at this time
ORA-01110: data file 6: '/u01/app/oracle/oradata/jack01.dbf'

----也无法进行TRUNCATE操作,说明在只读表空间上,对数据(说的是对象里面的数据)的所有操作都是不允许的,看起来数据还是比较安全的----
SQL> truncate table jack;
truncate table jack
               *
ERROR at line 1:
ORA-00372: file 6 cannot be modified at this time
ORA-01110: data file 6: '/u01/app/oracle/oradata/jack01.dbf'

----当表空间处于只读的时候,我们可以对表进行其他的修改,给表增加字段----
SQL> alter table jack add new_col varchar2(10);

Table altered.

SQL> alter table jack modify object_name varchar2(2000);

Table altered.

----在这里我们可以看到新的字段NEW_COL已经增加,OBJECT_NAME的属性已经修改成VARCHAR2(2000)----

SQL> desc jack;
Name                     Null?      Type
--------------------- -------- ----------------------------
OWNER                              VARCHAR2(30)
OBJECT_NAME                        VARCHAR2(2000)
SUBOBJECT_NAME                     VARCHAR2(30)
OBJECT_ID                          NUMBER
DATA_OBJECT_ID                     NUMBER
OBJECT_TYPE                        VARCHAR2(19)
CREATED                            DATE
LAST_DDL_TIME                      DATE
TIMESTAMP                          VARCHAR2(19)
STATUS                             VARCHAR2(7)
TEMPORARY                          VARCHAR2(1)
GENERATED                          VARCHAR2(1)
SECONDARY                          VARCHAR2(1)
NAMESPACE                          NUMBER
EDITION_NAME                       VARCHAR2(30)
NEW_COL                            VARCHAR2(10)

----无法删除字段----
SQL> alter table jack drop column new_col;
alter table jack drop column new_col
*
ERROR at line 1:
ORA-12985: tablespace 'JACK' is read only, cannot drop column

----可以删除索引和表----
SQL> alter tablespace jack read write;

Tablespace altered.

SQL> create index jack on jack(object_id);

Index created.

SQL> alter tablespace jack read only;

Tablespace altered.

SQL> drop index jack;

Index dropped.

SQL> create table persons(
PERSON_ID  NUMBER(8)    NOT NULL,
FIRST_NAME VARCHAR2(32) NOT NULL,
LAST_NAME  VARCHAR2(32) NOT NULL
) tablespace jack;

Table created.

SQL> drop table persons;

Table dropped.

总结:

凡是要对表空间上的数据进行修改的操作都不允许。比如:
INSERT  UPDATE  DELETE  TRUNCATE
实际上,只读表空间上的数据块连Oracle都不会修改(checkpoint_change#号从来都不会改变),这些修改数据的操作自然不被允许的。
那么,创建空表和给表增加字段或者修改字段的属性操作为什么就可以呢?因为此操作根本就不需要去触碰这个只读表空间,我们只要修改Oracle字典表中的信息就可以了(Oracle的对象属性是存储在数据字典中的,而字典表是存储在SYSTEM表空间上的),因此,这样的操作是被允许的。
同样的,删除一个字段,不仅仅要修改数据字典中表的相关信息,还涉及将该字段上的数据内容从表上抹掉,需要修改表空间上的数据块,因此,不被允许。

这样就清晰了:
凡是需要修改表空间数据块的操作,都不被允许。反之,则可以。

最后,删除这个表以及表上的索引是允许的,因为Oracle只需要从数据字典中将它的所有信息抹去就可以了。

猜你喜欢

转载自maosheng.iteye.com/blog/1913300