Oracle數據塊原理深入剖析-入門基礎時間:
數據塊(Oracle Data Blocks),本文簡稱為“塊”,是Oracle最小的存儲單位,Oracle數據存放在“塊”中。一個塊占用一定的磁盤空間。特別注意的是,這里的“塊”是Oracle的“數據塊”,不是操作系統的“塊”。
Oracle每次請求數據的時候,都是以塊為單位。也就是說,Oracle每次請求的數據是塊的整數倍。如果Oracle請求的數據量不到一塊,Oracle也會讀取整個塊。所以說,“塊”是Oracle讀寫數據的最小單位或者最基本的單位。
塊的標準大小由初始化參數DB_BLOCK_SIZE指定。具有標準大小的塊稱為標準塊(Standard Block)。塊的大小和標準塊的大小不同的塊叫非標準塊(Nonstandard Block)。同一數據庫中,Oracle9i及以上版本支持同一數據庫中同時使用標準塊和非標準塊。Oracle允許指定5種非標準塊(Nonstandard Block)。
操作系統每次執行I/O的時候,是以操作系統的塊為單位;Oracle每次執行I/O的時候,都是以Oracle的塊為單位。
Oracle數據塊大小一般是操作系統塊的整數倍。
數據塊的格式(Data Block Format)
塊中存放表的數據和索引的數據,無論存放哪種類型的數據,塊的格式都是相同的,塊由塊頭(header/Common and Variable),表目錄(Table Directory),行目錄(Row Directory),空余空間(Free Space)和行數據(Row Data)五部分組成,
如下圖所示。
塊頭(header/Common and Variable):存放塊的基本信息,如:塊的物理地址,塊所屬的段的類型(是數據段還是索引段)。 表目錄(Table Directory):存放表的信息,即:如果一些表的數據被存放在這個塊中,那么,這些表的相關信息將被存放在“表目錄”中。
行目錄(Row Directory):如果塊中有行數據存在,則,這些行的信息將被記錄在行目錄中。這些信息包括行的地址等。
行數據(Row Data):是真正存放表數據和索引數據的地方。這部分空間是已被數據行占用的空間。
空余空間(Free Space):空余空間是一個塊中未使用的區域,這片區域用于新行的插入和已經存在的行的更新。
頭部信息區(Overhead):我們把塊頭(header/Common and Variable),表目錄(Table Directory),行目錄(Row Directory)這三部分合稱為頭部信息區(Overhead)。頭部信息區不存放數據,它存放的整個塊的信息。頭部信息區的大小是可變的。一般來說,頭部信息區的大小介于84字節(bytes)到107字節(bytes)之間。
數據塊中自由空間的使用
當往數據庫中插入(INSERT)數據的時候,塊中的自由空間會減少;當對塊中已經存在的行進行修改(UPDATE)的時候(使記錄長度增加),塊中的自由空間也會減少。
DELETE語句和UPDATE語句會使塊中的自由空間增加。當使用DELETE語句刪除塊中的記錄或者使用UPDATE語句把列的值更改成一個更小值的時候,Oracle會釋放出一部分自由空間。釋放出的自由空間并不一定是連續的。通常情況下,Oracle不會對塊中不連續的自由空間進行合并。因為合并數據塊中不連續的自由空間會影響數據庫的性能。只有當用戶進行數據插入(INSERT)或者更新(UPDATE)操作,卻找不到連續的自由空間的時候,Oracle才會合并數據塊中不連續的自由空間。
對于塊中的自由空間,Oracle提供兩種管理方式:自動管理,手動管理
行鏈接和行遷移(Row Chaining and Migrating)
行鏈接(Row Chaining):如果我們往數據庫中插入(INSERT)一行數據,這行數據很大,以至于一個數據塊存不下一整行,Oracle就會把一行數據分作幾段存在幾個數據塊中,這個過程叫行鏈接(Row Chaining)。如下圖所示:
如果一行數據是普通行,這行數據能夠存放在一個數據塊中;如果一行數據是鏈接行,這行數據存放在多個數據塊中。
行遷移(Row Migrating):數據塊中存在一條記錄,用戶執行UPDATE更新這條記錄,這個UPDATE操作使這條記錄變長,這時候,Oracle在這個數據塊中進行查找,但是找不到能夠容納下這條記錄的空間,無奈之下,Oracle只能把整行數據移到一個新的數據塊。原來的數據塊中保留一個“指針”,這個“指針”指向新的數據塊。被移動的這條記錄的ROWID保持不變。行遷移的原理如下圖所示:
無論是行鏈接還是行遷移,都會影響數據庫的性能。Oracle在讀取這樣的記錄的時候,Oracle會掃描多個數據塊,執行更多的I/O。
塊中自由空間的自動管理
Oracle使用位圖(bitmap)來管理和跟蹤數據塊,這種塊的空間管理方式叫“自動管理”。自動管理有下面的好處:
◆易于使用
◆更好地利用空間
◆可以對空間進行實時調整
塊中自由空間的手動管理
用戶可以通過PCTFREE, PCTUSED來調整塊中空間的使用,這種管理方式叫手動管理。相對于自動管理,手動管理方式比較麻煩,不容易掌握,容易造成塊中空間的浪費。
PCTFREE參數用于指定塊中必須保留的最小空閑空間百分例。之所以要預留這樣的空間,是因為UPDATE時,需要這些空間。如果UPDATE時,沒有空余空間,Oracle就會分配一個新的塊,這會產生行遷移(Row Migrating)。
PCTUSED也是用于設置一個百分比,當塊中已使用的空間的比例小于這個百分比的時候,這個塊才被標識為有效狀態。只有有效的塊才被允許插入數據。
文章轉載自網管網:http://www.bitscn.com/pdb/oracle/200904/160356.html
ORACLE塊的分析
(一)
一直以來對“塊”的概念總是含混不清,從字面意義理解,只知道這是ORACLE存放數據的最小單位,然而它的內部世界如何呢,本人打算從今天開始連載幾篇文檔,對它進行深度分析。
通過很多文檔、資料,了解到了數據庫基本結構魚刺圖:
基本上每個對象對應一個段( Segment),只有分區對應多個段,這里的對象包括table,index,partition等等,段可以跨越多個數據文件。
每個段又有多個區(extent)來組成,這些區不能跨越多個數據文件,同時在系統使用過程中自動擴展。
最后是塊(block),所有的數據都是存放在塊中。為了適應操作系統,每個塊在創建數據庫的時候默認了一個大小,這個大小一般是8K,同時在9I及其以 后的版本中增加了不同大小的塊參數,這將在以后的實驗中體現。先說說這個8K大小的塊,一般來說,為了使得oracle運行讀寫數據文件的時候有一個合理 的吞吐量,這里的塊大小,都跟操作系統塊大小設為整數倍,例如ntfs格式化的磁盤文件,每個物理塊大小為4,這里oracle的塊大小為8,即是代表每 讀取一個oracle塊,其實物理上也就是讀取了兩個操作系統塊。 這里主要指的是數據文件存放在塊設備上,在實際的生產環境中,大部分情況都是將數據庫安裝在裸設備(RAW)也叫做原始分區之上。關于RAW將在以后進行 講解。
通過上面這段文字,我們可以了解到ORACLE基本的存儲結構,下一篇將針對塊的大小與存放數據大小來做實驗。
(二)
上一節了解到了ORACLE的存儲結構,這節講一講塊的大小與數據存放之間的關系。
大家都知道了在ORACLE環境中,所有的對象都是存放在塊中,這個塊大小與存放的記錄之間到底存在怎樣的關系呢?
做一個實驗看看:
創建一個表空間test
create tablespace test datafile '/oracle/oradata/test.dbf' size 100m;
創建一個用戶
create user test identified by test default tablespace test;
創建一個表
create table test.t1 (a1 number,a2 varchar2(100));
檢查段,可以發現在這個視圖中出現了名稱為T的段,段類型為TABLE,這個段里面分配了1個區,其中包含8個塊,大小為64K字節。
select segment_name,blocks,extents,bytes,segment_type,tablespace_name from dba_segments where owner='TEST';
SEGMENT_NAME BLOCKS EXTENTS BYTES SEGMENT_TYPE TABLESPACE_NAME
---------- ---------- ---------- ---------- ------------------ ----------
T 8 1 65536 TABLE TEST
檢查區,可以發現在這個視圖中出現了一個區,區號為0,包含8個塊,大小為64K字節。
select segment_name,segment_type,extent_id,blocks,bytes from dba_extents where owner='TEST';
SEGMENT_NAME SEGMENT_TYPE EXTENT_ID BLOCKS BYTES
---------- ------------------ ---------- ---------- ----------
T TABLE 0 8 65536
檢查塊,可以發現這里沒有載入到內存的塊,由此斷定,在數據未寫入的時候,內存中并沒有存放數據的塊。
select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;
未選定行
插入10行數據,進行測試。
SQL> declare
2 i number
3 ;
4 begin
5 for i in 1..10 loop
6 execute immediate 'insert into test.t values (:x,:y)' using i,i;
7 end loop;
8 end;
9 /
PL/SQL 過程已成功完成。
再次查看v$bh視圖,檢查內存中是否使用到了塊。
select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;
FILE# BLOCK# CLASS# STATU XNC OBJD
---------- ---------- ---------- ----- ---------- ----------
1 28089 4 xcur 0 11038
1 28090 1 xcur 0 11038
哈哈,果然出現了數據,說明在數據插入的表的時候在內存中已經載入了分配的塊,同時在這些塊中寫入了數據,這里占用了兩個塊,塊號分別為28089,28090,其中我們可以根據CLASS#來判斷出他們屬于不同類型。
(三)
這一節緊接著上一節來說。
上一節通過實驗,我們了解到,塊的創建和讀取流程,不過只是針對一個會話的,現在我們來看看在一個會話中插入數據之后,同時在另外一個會話查詢數據,這樣的情況會對塊有什么影響。
打開一個新的會話, 然后執行如下命令:
查詢表,由于插入數據的事務沒有提交,這里在另外的會話中就看不到任何數據,深深體現了ORACLE的多版本一致性
select * from test_gao.t;
未選定行
查詢視圖v$bh,看是否有了變化
select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;
FILE# BLOCK# CLASS# STATU XNC OBJD
---------- ---------- ---------- ----- ---------- ----------
1 28089 4 xcur 0 11038
1 28090 1 cr 0 11038
1 28090 1 cr 0 11038
1 28090 1 xcur 0 11038
果然和上一節查詢出來的結果不同,多了紅色字體標識出來的兩行,大家可以看到這兩行的STATUS字段值為cr,什么是cr呢?它是Consistency Read(一致性讀取)的縮寫。從這里可以看出28090這個塊被兩個會話進行了操作。
在第一個會話中回滾事務會發生什么呢?看下面的操作:
會話1:執行rollback
SQL> rollback;
回退已完成。
再次查詢v$bh視圖,看看什么情況
select file#,block#,class#,status,xnc,objd from v$bh where objd=11038;
FILE# BLOCK# CLASS# STATU XNC OBJD
---------- ---------- ---------- ----- ---------- ----------
1 28089 4 xcur 0 11038
1 28090 1 cr 0 11038
1 28090 1 cr 0 11038
1 28090 1 xcur 0 11038
結果還是一樣,說明在事務回滾之后,塊還是處于一致讀取的狀態。
(四)
我們繼續上一節的話題。
關閉數據庫實例
SQL> shutdown immediate
數據庫已經關閉。
已經卸載數據庫。
重新打開數據庫
SQL>startup
ORACLE 例程已經啟動。
Total System Global Area 253214492 bytes
Fixed Size 454428 bytes
Variable Size 117440512 bytes
Database Buffers 134217728 bytes
Redo Buffers 1101824 bytes
數據庫裝載完畢。
數據庫已經打開。
檢查v$bh視圖
select file#,block#,class#,status,xnc,objd from v$bh where objd=11038;
未選定行
說明在沒有進行塊中數據的相關操作的時候,并沒有從物理文件中提取塊到內存。
執行查詢或者插入、更新的SQL語句
SQL> insert into test.t values (200,200);
已創建 1 行。
再次檢查v$bh視圖
SQL> select file#,block#,class#,status,xnc,objd from v$bh where objd=11038;
FILE# BLOCK# CLASS# STATU XNC OBJD
---------- ---------- ---------- ----- ---------- ----------
1 28089 4 xcur 0 11038
1 28090 1 xcur 0 11038
總結:在沒有進行物理I/O的時候,v$bh視圖中不會出現相關的塊信息,同時證明此視圖中存放的乃是數據文件塊放到內存中的“塊”信息。
實例講解Oracle 9i數據壞塊的處理
筆者在一臺生產用測試庫上SELECT一個表時出現ORA-01578,一個塊損壞,以前學習過塊損壞怎么處理,到還真沒遇到過,今天總算讓我遇到了,還是一臺生產用測試庫,就不用很緊張了。
數據庫版本是9.2.0.4,Oracle9i的RMAN有一個blockrecover命令,可以在線修復壞塊,以下就是使用RMAN修復壞塊的過程。
SQL> conn owi/owi |
報ORA-01578數據塊損壞,以下使用RMAN命令查詢是否可以使用blockrecover命令恢復以及怎樣恢復
使用rman登錄catalog數據庫
[ora9@rmanserver ~]$ rman target sys/oracle@dpa catalog rman/rman Recovery Manager: Release 9.2.0.8.0 - Production Copyright (c) 1995, 2002, Oracle Corporation. All rights reserved. connected to target database: DPA (DBID=843495022) |
查找最近datafile 15的全備份,今天下午剛做了一次RMAN的全備份
RMAN> list backup of datafile 15;
List of Backup Sets
===================
BS Key Type LV Size Device Type Elapsed Time Completion Time
------- ---- -- ---------- ----------- ------------ ---------------
643 Full 64K DISK 00:00:27 16-MAR-09
BP Key: 650 Status: AVAILABLE Tag: TAG20090316T154352
Piece Name: /d02/fullbackup/20090316_data_24_1
List of Datafiles in backup set 643
File LV Type Ckp SCN Ckp Time Name
---- -- ---- ---------- --------- ----
15 Full 11856250905 16-MAR-09 /d01/app/oracle/oradata/dpa/dpa01.dbf
查找SCN 11856250905 以后的archivelog是否有備份
RMAN> list backup of archivelog scn from 11856250905 |
查找sequence 110 以后的archivelog是否有備份
RMAN> list copy of archivelog from sequence 110; List of Archived Log Copies 查詢online archive log SQL> select sequence#,members,archived,status from v$log; SEQUENCE# MEMBERS ARC STATUS |
從以上查詢中可以看出datafile 15有一次最近的全備份,有全備份以來的所有archivelog,online redo log
下面開始blockreocver,其實命令很簡單
RMAN> blockrecover datafile 15 block 18;
Starting blockrecover at 16-MAR-09
allocated channel: ORA_DISK_1
channel ORA_DISK_1: sid=16 devtype=DISK
channel ORA_DISK_1: restoring block(s)
channel ORA_DISK_1: specifying block(s) to restore from backup set
restoring blocks of datafile 00015
channel ORA_DISK_1: restored block(s) from backup piece 1
piece handle=/d02/fullbackup/20090316_data_24_1 tag=TAG20090316T154352 params=NULL
channel ORA_DISK_1: block restore complete
starting media recovery
archive log thread 1 sequence 111 is already on disk as file /d02/arch/1_111.dbf
archive log thread 1 sequence 112 is already on disk as file /d02/arch/1_112.dbf
channel ORA_DISK_1: starting archive log restore to default destination
channel ORA_DISK_1: restoring archive log
archive log thread=1 sequence=109
channel ORA_DISK_1: restoring archive log
archive log thread=1 sequence=110
channel ORA_DISK_1: restored backup piece 1
piece handle=/d02/fullbackup/20090316_arch_28 tag=TAG20090316T154731 params=NULL
channel ORA_DISK_1: restore complete
media recovery complete
Finished blockrecover at 16-MAR-09
再SELECT一下表DPA_HISTORY
SQL> select * from dpa_history;
PRODLINEID BARCODE PA
---------- ------------------------------ --
7 S*33040-D8311050149512B 03
7 S*33040-D8311050143512B 03
7 S*33040-D8311050140512B 03