Oracle Read-only Tablespace(只讀表空間)


一、本文說明

    本文整理於譚大師的讓Oracle跑得更快1。

二、只讀表空間與數據備份和恢復的關系

    表空間設置成只讀之后,只需要執行一次備份操作即可,在后續備份時不再需要考慮這些表空間的備份。

    原因很容易理解,這些表空間中的數據已經不再改變,存儲在表空間中的數據狀態始終保持在表空間設置為Read-Only那一刻,就像是給表空間做了一個快照一樣,Oracle也不需要對它們進行額外的恢復工作,比如應用歸檔。

    看下面的例子:

    我們創建兩個表空間,一個是只讀(Read-Only)的,一個是常規的(Read-Write),下面來比較這兩個表空間數據文件的變化情況。

 1 SQL> create tablespace readonly datafile '/u01/app/oracle/oradata/readonly01.dbf' size 10m;
 2 
 3 Tablespace created.
 4 
 5 SQL> create tablespace readwrite datafile '/u01/app/oracle/oradata/readwrite01.dbf' size 10m;
 6 
 7 Tablespace created.
 8 
 9 SQL> alter tablespace readonly read only;
10 
11 Tablespace altered.

    這樣,我們就創建了兩個表空間readonly和readwrite,並把表空間readonly的狀態設置為只讀。

1 SQL> select name,file#,checkpoint_change# from v$datafile where name like '%read%';
2 
3 NAME                           FILE# CHECKPOINT_CHANGE#
4 --------------------------------------------- ---------- ------------------
5 /u01/app/oracle/oradata/readonly01.dbf               6        4342263
6 /u01/app/oracle/oradata/readwrite01.dbf            7        4341997

    我們先記錄下當前狀態下兩個表空間數據文件的SCN號,這個號表示表空間數據文件在Oracle數據庫運行時某個時間點的狀態。SCN是Oracle里面的一個序號,用來標識一個先后順序,通常用於保護數據塊的完整性或者一致性的查詢。
當數據塊做了修改,它的SCN值就會發生相應的改變。

1 SQL> alter system checkpoint;
2 
3 System altered.

    我們發出一個CHECKPOINT命令,這個命令實際上是將內存中的臟數據塊寫入到磁盤上的文件中,並更新文件頭部信息,以保證數據塊中數據的一致性。

1 SQL> select name,file#,checkpoint_change# from v$datafile where name like '%read%';
2 
3 NAME                                             FILE#   CHECKPOINT_CHANGE#
4 --------------------------------------------- ---------- ------------------
5 /u01/app/oracle/oradata/readonly01.dbf             6        4342263
6 /u01/app/oracle/oradata/readwrite01.dbf            7        4343696

    我們看到,執行了CHECKPOINT命令之后,READWRITE表空間數據文件的SCN號發生了變化,這說明這個表空間相比之前的狀態,它的數據文件已經產生了變化。
盡管我們沒有對這個表空間做任何操作,但不能保證Oracle不這樣做(實際上,這里是表空間數據文件的文件頭數據塊產生了變化)。我們知道,只要數據文件的SCN號發生了變化,Oracle就需要進行恢復;而這里,READONLY的SCN號並沒有變化,看起來就像靜止在那里一樣。

    這就是說,如果此時Oracle數據庫出現問題,比如DOWN掉了,在數據庫重新OPEN時,READONLY表空間是不需要恢復的,因為它的狀態依然保持在將它置於READ-ONLY那一刻,那一刻數據庫是好的。

    而READWRITE表空間就不同了,如果此時數據庫DOWN掉了,它就需要進行恢復,因為這個表空間上的數據塊狀態是持續更新的,它需要通過聯機日志(或者歸檔日志)將它恢復到最后Oracle數據庫DOWN掉時的狀態。

    我們繼續來看,現在將這兩個表空間的狀態改為離線。

 1 SQL> alter tablespace readonly offline;
 2 
 3 Tablespace altered.
 4 
 5 SQL> alter tablespace readwrite offline;
 6 
 7 Tablespace altered.
 8 
 9 SQL> col name for a45;
10 SQL> select name,file#,checkpoint_change# from v$datafile where name like '%read%';
11 
12 NAME                                             FILE#   CHECKPOINT_CHANGE#
13 --------------------------------------------- ---------- ------------------
14 /u01/app/oracle/oradata/readonly01.dbf             6        4342263
15 /u01/app/oracle/oradata/readwrite01.dbf            7        4351566

    我們看到,READONLY表空間的SCN號依然保持不變。

 1 SQL> alter system checkpoint;
 2 
 3 System altered.
 4 
 5 SQL> select name,file#,checkpoint_change# from v$datafile where name like '%read%';
 6 
 7 NAME                                            FILE#    CHECKPOINT_CHANGE#
 8 --------------------------------------------- ---------- ------------------
 9 /u01/app/oracle/oradata/readonly01.dbf             6        4342263
10 /u01/app/oracle/oradata/readwrite01.dbf            7        4351566

    當數據文件狀態為離線時,不論之前它是只讀還是讀寫表空間,它的狀態都不再改變。

    現在,我們把這兩個表空間的狀態重新改為在線。

 1 SQL> alter tablespace readonly online;
 2 
 3 Tablespace altered.
 4 
 5 SQL> alter tablespace readwrite online;
 6 
 7 Tablespace altered.
 8 
 9 SQL> select name,file#,checkpoint_change# from v$datafile where name like '%read%';
10 
11 NAME                                            FILE#    CHECKPOINT_CHANGE#
12 --------------------------------------------- ---------- ------------------
13 /u01/app/oracle/oradata/readonly01.dbf             6        4342263
14 /u01/app/oracle/oradata/readwrite01.dbf            7        4351660

    我們看到,READWRITE表空間的SCN號再次改變了。實際上,在把READWRITE表空間的狀態改為在線時,Oracle對它進行了恢復操作,使它的狀態和數據庫當前狀態一致;而READONLY表空間依然靜止不動地保持着它最初的狀態,和數據庫的變化毫無關系。
這樣看來,在備份和恢復上,對只讀表空間備份一次就夠了;而對其他的讀寫表空間的備份,可能需要定期做全備份或者增量備份,同時還需要備份恢復時所需要的歸檔日志。這些備份集不但需要大量的磁盤空間,而且恢復時也可能會相當耗時。

在這里有一個專題是討論只讀表空間的恢復的: 《只讀數據文件損壞恢復》

三、只讀表空間對於數據庫的啟動和關閉的影響

    將不再有數據變化的一些表空間置於Read-Only狀態,可以加快數據庫關閉和啟動的時間,原因是Oracle不會再對設置為Read-Only狀態的表空間的數據文件進行處理;或者說,在數據同步(數據塊從內存刷新到磁盤上)時,忽略這些文件。

 1 SQL> create tablespace test datafile '/u01/app/oracle/oradata/test01.dbf' size 10m,
 2   2    '/u01/app/oracle/oradata/test02.dbf' size 10m,
 3   3    '/u01/app/oracle/oradata/test03.dbf' size 10m,
 4   4    '/u01/app/oracle/oradata/test04.dbf' size 10m,
 5   5    '/u01/app/oracle/oradata/test05.dbf' size 10m,
 6   6    '/u01/app/oracle/oradata/test06.dbf' size 10m,
 7   7    '/u01/app/oracle/oradata/test07.dbf' size 10m,
 8   8    '/u01/app/oracle/oradata/test08.dbf' size 10m,
 9   9    '/u01/app/oracle/oradata/test09.dbf' size 10m,
10  10    '/u01/app/oracle/oradata/test10.dbf' size 10m,
11  11    '/u01/app/oracle/oradata/test11.dbf' size 10m,
12  12    '/u01/app/oracle/oradata/test12.dbf' size 10m,
13  13    '/u01/app/oracle/oradata/test13.dbf' size 10m,
14  14    '/u01/app/oracle/oradata/test14.dbf' size 10m,
15  15    '/u01/app/oracle/oradata/test15.dbf' size 10m,
16  16    '/u01/app/oracle/oradata/test16.dbf' size 10m,
17  17    '/u01/app/oracle/oradata/test17.dbf' size 10m,
18  18    '/u01/app/oracle/oradata/test18.dbf' size 10m,
19  19    '/u01/app/oracle/oradata/test19.dbf' size 10m,
20  20    '/u01/app/oracle/oradata/test20.dbf' size 10m;
21 
22 Tablespace created.

    創建一個包含20個數據文件的表空間,目的是使后面的操作效果比較明顯。

1 SQL> create table test (id int) tablespace test;
2 
3 Table created.

    向表中插入一些數據,產生一些變化的數據塊。

    下面我們來看看數據庫進行實例恢復的用時情況。

Mon Feb 04 06:38:48 2013
Shutting down instance (abort)
License high water mark = 3
USER (ospid: 3756): terminating the instance
Instance terminated by USER, pid = 3756
Mon Feb 04 06:38:50 2013
Instance shutdown complete
Mon Feb 04 06:39:00 2013
Starting ORACLE instance (normal)
。。。。。。
Mon Feb 04 06:39:11 2013
QMNC started with pid=21, OS id=3938 
Completed: ALTER DATABASE OPEN

    上面是從alert日志文件中的內容,當我們執行shutdown abort后再啟動數據庫。從上面可以看出數據庫啟動的時間是11秒,里面包含實例恢復的時間。
我們將表空間設置為只讀。

SQL> alter tablespace test read only;

Tablespace altered.

SQL> shutdown abort;
ORACLE instance shut down.
SQL> startup
ORACLE instance started.

Total System Global Area  330600448 bytes
Fixed Size            1336344 bytes
Variable Size          247466984 bytes
Database Buffers       75497472 bytes
Redo Buffers            6299648 bytes
Database mounted.
Database opened.
----alert日志信息----
Mon Feb 04 06:46:16 2013
Shutting down instance (abort)
License high water mark = 3
USER (ospid: 3934): terminating the instance
Instance terminated by USER, pid = 3934
Mon Feb 04 06:46:17 2013
Instance shutdown complete
Mon Feb 04 06:46:21 2013
Starting ORACLE instance (normal)
。。。。。。
Mon Feb 04 06:46:30 2013
CJQ0 started with pid=21, OS id=4128 
Completed: ALTER DATABASE OPEN
數據庫啟動的時間為9秒,比上個例子少了2秒。

    這個效果不明顯,如果在一個大的數據庫中,數據文件的個數成百上千,這種差異就會進一步拉大。

實際上,當表空間設置為Read-Only時,數據庫啟動后,並不會對數據文件進行更新(修改),這在一定程度上縮小了數據庫啟動的時間。

四、只讀表空間可以防止數據被意外刪除和修改

    將表空間設置為只讀還有一個目的,就是可以防止數據被意外刪除和修改。

 ----創建一個jack表空間----
1
SQL> create tablespace jack datafile '/u01/app/oracle/oradata/jack01.dbf' size 500m; 2 3 Tablespace created. 4 5 SQL> show user; 6 USER is "JACK" ----創建一張表jack----
7
SQL> create table jack tablespace jack as select * from dba_objects; 8 9 Table created. 10 ----將表空間狀態設置為只讀----
11
SQL> alter tablespace jack read only; 12 13 Tablespace altered. 14 ----做一些修改數據的操作,無法進行DELETE操作----
15
SQL> delete from jack; 16 delete from jack 17 * 18 ERROR at line 1: 19 ORA-00372: file 6 cannot be modified at this time 20 ORA-01110: data file 6: '/u01/app/oracle/oradata/jack01.dbf' 21 ----無法進行UPDATE操作----
22
SQL> update jack set object_id=object_id*10; 23 update jack set object_id=object_id*10 24 * 25 ERROR at line 1: 26 ORA-00372: file 6 cannot be modified at this time 27 ORA-01110: data file 6: '/u01/app/oracle/oradata/jack01.dbf' 28 ----無法進行INSERT操作,也就是說,對於只讀表空間上的數據,無法進行DML操作。----
29
SQL> insert into jack select * from dba_objects; 30 insert into jack select * from dba_objects 31 * 32 ERROR at line 1: 33 ORA-00372: file 6 cannot be modified at this time 34 ORA-01110: data file 6: '/u01/app/oracle/oradata/jack01.dbf' 35 ----也無法進行TRUNCATE操作,說明在只讀表空間上,對數據(說的是對象里面的數據)的所有操作都是不允許的,看起來數據還是比較安全的----
36
SQL> truncate table jack; 37 truncate table jack 38 * 39 ERROR at line 1: 40 ORA-00372: file 6 cannot be modified at this time 41 ORA-01110: data file 6: '/u01/app/oracle/oradata/jack01.dbf' 42 ----無法創建對象----
43
SQL> create table echo tablespace jack as select * from dba_objects; 44 create table echo tablespace jack as select * from dba_objects 45 * 46 ERROR at line 1: 47 ORA-01647: tablespace 'JACK' is read-only, cannot allocate space in it 48 49 ----當表空間處於只讀的時候,我們可以對表進行其他的修改,給表增加字段----
50
SQL> alter table jack add new_col varchar2(10); 51 52 Table altered. 53 54 SQL> alter table jack modify object_name varchar2(2000); 55 56 Table altered. 57 ----在這里我們可以看到新的字段NEW_COL已經增加,OBJECT_NAME的屬性已經修改成VARCHAR2(2000)----
58
SQL> desc jack; 59 Name Null? Type 60 --------------------- -------- ---------------------------- 61 OWNER VARCHAR2(30) 62 OBJECT_NAME VARCHAR2(2000) 63 SUBOBJECT_NAME VARCHAR2(30) 64 OBJECT_ID NUMBER 65 DATA_OBJECT_ID NUMBER 66 OBJECT_TYPE VARCHAR2(19) 67 CREATED DATE 68 LAST_DDL_TIME DATE 69 TIMESTAMP VARCHAR2(19) 70 STATUS VARCHAR2(7) 71 TEMPORARY VARCHAR2(1) 72 GENERATED VARCHAR2(1) 73 SECONDARY VARCHAR2(1) 74 NAMESPACE NUMBER 75 EDITION_NAME VARCHAR2(30) 76 NEW_COL VARCHAR2(10) 77 ----無法刪除字段----
78
SQL> alter table jack drop column new_col; 79 alter table jack drop column new_col 80 * 81 ERROR at line 1: 82 ORA-12985: tablespace 'JACK' is read only, cannot drop column

總結:

凡是要對表空間上的數據進行修改的操作都不允許。比如:

INSERT

UPDATE

DELETE

TRUNCATE

    實際上,只讀表空間上的數據塊連Oracle都不會修改(SCN號從來都不會改變),這些修改數據的操作自然不被允許的。

    那么,給表增加字段或者修改字段的屬性操作為什么就可以呢?

    因為此操作根本就不需要去觸碰這個只讀表空間,我們只要修改Oracle字典表中的信息就可以了(Oracle的對象屬性是存儲在數據字典中的,而字典表是存儲在SYSTEM表空間上的),因此,這樣的操作是被允許的。

    還有,創建對象為什么不可以?它不也是修改數據字典嗎?不全是,它同時還需要在表空間上為對象分配空間,這就需要訪問表空間,需要修改數據塊,所以,不可以。

    同樣的,刪除一個字段,不僅僅要修改數據字典中表的相關信息,還涉及將該字段上的數據內容從表上抹掉,需要修改表空間上的數據塊,因此,不被允許。

這樣就清晰了:

    凡是需要修改表空間數據塊的操作,都不被允許。

    反之,則可以。

最后,刪除這個表以及表上的索引是允許的,因為Oracle只需要從數據字典中將它的所有信息抹去就可以了。

 1 SQL> alter tablespace jack read write;
 2 
 3 Tablespace altered.
 4 
 5 SQL> create index jack on jack(object_id);
 6 
 7 Index created.
 8 
 9 SQL> alter tablespace jack read only;
10 
11 Tablespace altered.
12 
13 SQL> drop index jack;
14 
15 Index dropped.
16 
17 SQL> drop table jack purge;
18 
19 Table dropped.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM