回滾段探究

[url]http://blog.csdn.net/biti_rainy/archive/2004/07/03/32810.aspx[/url]
l 前言
對於oracle的回滾段的分配與管理,實際上不那麼複雜,當然如果我們從原理甚至從oracle internal的角度深究相關問題的話有不是一件容易的事。但對於我們普通開發人員和DBA來說,重要的是在概念上清晰,原理上了解,使用上熟悉。要做到這一點,其實並不是一件困難的事情。問題的根源在於,很少有中文文章就回滾段進行清晰的介紹和整理,而對於oracle document,能沉下心來慢慢讀的人實在太少,雖然我不得不承認如果您認真的讀了oracle concepts 中關於回滾段部分,這裏的大部分內容對於您來說已經是很熟悉的東西,但是,我還是願意拋開oracle document來談我的理解,在現實中我們到底遇見怎樣的問題。在瑣碎的文檔中,抓不住問題的關鍵部分是我們閱讀的最大的障礙。又由於過於瑣碎使得難以在宏觀上進行把握,從而打擊了我們堅持讀下去的信心。所以也才讓我有產生寫這點文字的念頭,其中一部分是重複了oracle文檔中的內容,只不過可能來源於文檔的不同地方。在這文章裏我打算從回滾段的作用、原理、分配與管理、診斷、常見問題等幾個方面來闡述相關內容。



l 什麼是回滾段
如果想按照數學上的定義來定義回滾段,我想是乏味的、抽象的。比如可以說是用來保存數據變化前映像而提供一致讀和保障事務完整性的一段磁盤存儲區域。做應用的人,往往並不是關心概念或者定義而是關心具體的使用,就好比我們天天都在管理使用數據庫但卻根本記不住數據庫的定義一樣。事實上我們的工作也不要求我們記得數據庫定義。重要的是,對於我們的數據庫,我們該怎麼具體去理解它、怎麼去使用和管理它。

我們大概知道回滾段是在磁盤上的一段空間,當一個事務開始的時候,會首先把變化前的數據和變化後的數據先寫入日誌緩衝區,然後把變化前的數據寫入回滾段,最後纔在數據緩衝區中修改數據(日誌緩衝區內容在滿足一定的條件後可能被寫入磁盤,但在事務提交的時候日誌必須寫入磁盤,而數據緩衝區中數據依賴於檢查點的發生和DBWR進程的活動,在這裏不繼續討論相關內容)。舉個例子,當我們做如下操作



SQL> update t set object_id = '0' where object_id = '12344';



1 row updated.



SQL> commit;



Commit complete.



這時數據庫首先把該語句的整個操作包括數據’0’和’12344’寫入日誌緩衝區,然後把數據’12344’和一些相關信息寫入回滾段,最後把’0’修改到數據緩衝區。當發出提交命令的時候,如果日誌緩衝區內容還沒有寫入日誌文件則必須寫進日誌文件,回滾段把該事務標記爲已經提交,數據緩衝區中塊的這些事務也標記爲已經提交(在大事務的情況下如果數據緩衝區中塊已經被寫入磁盤或者該事務更改的塊超過數據緩衝區總大小的10%則不再對這些塊標誌該事務爲已經提交,這會影響到我們下次讀該塊)。當然如果我們回退這個事務,則數據庫將把回滾段中數據’12344’讀出來寫回數據緩衝區(數據緩衝區已經被修改爲’0’),這個回退的變化本身也被寫入日誌,這就是回退的過程。我們可以看出如果事務很大、數據緩衝區中事務數據如果已經被寫入磁盤了,那這簡直就是一個代價極其昂貴的操作。所以通常來說,我們認爲一個系統中的事務的回退率應該比較低,否則應該檢查系統是否正常或者程序設計思路是否存在問題。我們可以通過下面查詢來衡量數據庫啓動以來的事務回退率,如果發現transaction rollbacks/( transaction rollbacks + user commits)太高一定要引起重視。



SQL> select name,value from v$sysstat where name in ('user commits','transaction rollbacks');



NAME VALUE

---------------------------------------------------------------- ----------

user commits 12532

transaction rollbacks 21



SQL>



在這裏我們要指出的關於回滾段存儲的數據,假如是delete操作,則回滾段將會記錄整個行的數據,假如是update,則回滾段只記錄被修改了的字段的變化前的數據(前映像),也就是沒有被修改的字段是不會被記錄的,假如是insert,則回滾段只記錄插入記錄的rowid。這樣假如事務提交,那回滾段中簡單標記該事務已經提交;假如是回退,則如果操作是是delete,回退的時候把回滾段中數據重新寫回數據塊,操作如果是update,則把變化前數據修改回去,操作如果是insert,則根據記錄的rowid把該記錄刪除。這個過程,可以看作保障事務的完整性,保障數據不丟失。

這裏我們介紹一下一致性讀取,英文是consistent reads。對於oracle而言,查詢的結果集是根據時間點來判定的。Oracle內部通過系統改變號SCN作爲相對時間點的標準,任何對數據庫的改變都會產生SCN,這個一個正整數,對數據塊的數據改變的時候會把該改變所對應的SCN記錄在塊中。假設查詢開始的時候的SCN爲T,則在查詢所掃描的數據塊中,如果數據的COMMIT SCN小於T,則查詢接受該數據,如果COMMIT SCN大於T或者說還沒有產生COMMIT SCN,則查詢會嘗試去回滾段中查找數據。這是爲了保證數據的讀取的時間點的一致性,所以叫一致性讀。

在通過回滾段中獲取數據的時候,本質上是把數據緩衝區中數據塊做一份拷貝,然後將回滾段中記錄的內容恢復到該塊中,然後查詢使用這個塊來進行讀取。這樣的塊的數量,如果大家有興趣可以通過SYS用戶登陸到數據庫然後查詢獲得



SQL> select count(*) from x$bh where state = 3;



COUNT(*)

----------

15



SQL>





我們很可能產生這樣的困惑,回滾段的塊是否存在於SGA中?如果有存在那爲何不見有參數設置?真實情況是,回滾段的塊跟其他數據文件的塊一樣,都在SGA中,也都是數據緩衝區中的一份子。同樣地,對於oracle8以上的版本的數據庫,我們可以通過查詢x$bh來確定回滾段所佔的塊的多少。我們可以參考v$rollstat事視圖和x$bh表,在x$bh中的class字段,如果是回滾段塊,假設回滾段USN爲n,則回滾段頭class爲11+2n,回滾段塊爲12+2n。我們來看看實際的例子

SQL> select usn from v$rollstat;



USN

----------

0

1

2

3

4

5

6

7

9



9 rows selected.



SQL>

從回滾段編號中我們可以看到編號8的回滾段已經被刪除了,總共9個回滾段。



SQL> select class,count(*) from x$bh where class > 10 group by class;



CLASS COUNT(*)

---------- ----------

11 1

12 2

13 1

14 1

15 1

16 1

17 1

18 982

19 1

20 1

21 1



CLASS COUNT(*)

---------- ----------

22 1

23 1

24 1

25 1

26 1

29 1

30 1



18 rows selected.



SQL>

從這裏我們可以看出,回滾段編號爲8的class應該爲27、28的塊是沒有。回滾段頭始終都是一個塊,class=18(usn=3)的回滾段使用的塊比較多,是因爲我的數據庫剛啓動,剛纔執行了下面的語句。



SQL> delete from t;



25374 rows deleted.



SQL> commit;



Commit complete.



SQL>



l 回滾段的分配和使用
當事務產生的時候,數據庫會給事務分配一個回滾段。當然我們可以指定事務使用某個回滾段。在我的測試用的數據庫中,有如下回滾段



SQL> select SEGMENT_ID ,SEGMENT_NAME from dba_rollback_segs;



SEGMENT_ID SEGMENT_NAME

---------- ------------------------------

0 SYSTEM

1 RBS0

2 RBS1

3 RBS2

4 RBS3

5 RBS4

6 RBS5

7 RBS6

9 RBS12



9 rows selected.



SQL>

如果我們要指定事務使用某個回滾段,如下



SQL> set transaction use rollback segment rbs6;



Transaction set.



SQL> insert into t select * from all_objects;



25649 rows created.



SQL> commit;



Commit complete.



SQL>

如果我們不人爲的指定使用哪個回滾段,則數據庫會根據回滾段中事務來權衡,以使得所有回滾段中事務壓力儘可能平均。我們考慮存在非系統回滾段的情況(這也是絕大多數系統的情況,除非因爲DBA嚴重錯誤纔會使得系統只存在系統回滾段),在這種情況下我們發出的事務不會去使用系統回滾段,這時系統回滾段只用於系統級使用,比如create、drop、truncate等發生的時候的系統級的數據字典的回滾記錄。數據庫爲我們發出的事務選擇非系統回滾段,同一個事務不能跨越回滾段,也就是說即使其他回滾段還很空閒,該大事務也只能使用被分配的回滾段即使該回滾段擴展。

接下來我們來考究單個回滾段內的使用、擴展、回縮的問題。一個回滾段至少包含2個extent。每個回滾段有一個回滾段頭,回滾段頭是一個block,裏面主要記錄了事務表信息。當產生一個事務的時候,就在回滾段頭的事務表中記錄一條信息,該信息中包含了事務標誌、事務狀態、使用的回滾段塊數等等信息。我們假定新創建的一個回滾段存在extent 1,2,3,4,5。當第一個事務分配到回滾段中的時候,除了事務表信息,該事務從extent 1的第二個block開始使用,該事務提交後陸續不斷的事務到來並提交,假設我們已經使用到了extent 5的末尾。這時再來事務內容需要寫入,則重新使用extent 1 的第二個block。這樣循環使用回滾段空間。同理回滾段頭的事務表也是如此循環使用。循環的次數,可以通過如下查詢獲得

SQL> select usn,WRAPS from v$rollstat;



USN WRAPS

---------- ----------

0 0

1 15

2 15

3 15

4 15

5 12

6 15

7 17

9 12



9 rows selected.



SQL>

那麼我們會有一個問題,那就是既然回滾段是循環使用的,那爲什麼會擴展呢?注意在上面的例子中,所有的事務都是迅速提交了的。那我們現在假定這樣一種情況,存在一個事務,假設在extent 3 中有一個事務一直沒有提交,然後回滾段一直循環使用到了extent 2。當extent 2使用完畢的時候發現extent 3中存在未提交事務,這是即使extent 4,5,1中的事務都已經提交,當前事務也不能越過extent 3而去使用後面的可使用的extent,這時該回滾段就擴展新的extent,假定爲extent 2-1。在數據庫中實際上回滾段的extent之間是通過指針連起來的一個單向循環的鏈表結構。擴展的時候相當於在鏈表中插入一個節點extent 2-1,但節點2-1的下一個extent依然是 extent 3,假如2-1使用完畢發現extent 3仍然存在未提交事務回滾段會繼續擴展。

我們做個例子,在SQLPLUS 1 中運行不提交(我們在v$rollstat 和 dba_rollback_segs中分別查詢發現usn =5的回滾段對應了名字 rbs4)



SQL> select a.usn,b.segment_name from v$rollstat a,dba_rollback_segs b

2 where a.usn = b.segment_id;



USN SEGMENT_NAME

---------- ------------------------------

0 SYSTEM

1 RBS0

2 RBS1

3 RBS2

4 RBS3
5 RBS4
6 RBS5

7 RBS6

9 RBS12



9 rows selected.



SQL>

SQL> select usn,rssize "rollback segment size" from v$rollstat where usn = 5;



USN rollback segment size

---------- ---------------------

5 4186112



SQL> set transaction use rollback segment rbs4;



Transaction set.



SQL> update t_small set object_id = 1;



100 rows updated.



打開SQLPLUS 2運行
begin

for i in 1..1000 loop

set transaction use rollback segment rbs4;

update t set object_id = i where rownum < 101;

commit;

end loop;

end;

SQL> select usn,rssize "rollback segment size" from v$rollstat where usn = 5;



USN rollback segment size

---------- ---------------------

5 55042048


現在我們來看在一個獨立的session中運行下面的查詢並對比查詢前後的回滾段變化。





SQL> select usn,rssize "rollback segment size" from v$rollstat where usn= 4;



USN rollback segment size

---------- ---------------------

4 4186112


SQL> begin

2 for i in 1..1000 loop

3 set transaction use rollback segment rbs3;

4 update t set object_id = i where rownum < 101;

5 commit;

6 end loop;

7 end;

8 /



PL/SQL procedure successfully completed.



SQL> select usn,rssize "rollback segment size" from v$rollstat where usn= 4;



USN rollback segment size

---------- ---------------------

4 4186112



SQL>



在這兩個例子中我們很明顯地看到了回滾段是否擴展的對比。那麼,做完第二個例子後,我再回過頭來查詢原來擴展的比較大的回滾段,發現又變成4M了



SQL> select usn,rssize "rollback segment size" from v$rollstat where usn= 5;



USN rollback segment size

---------- ---------------------

5 4186112



SQL>

回滾段在擴展後,是要回縮的。假設回滾段當前extent n,使用完畢將準備使用extent n+1 的時候(extent n+1 無活動事務),如果設置了optimal並且回滾段大於 optimal設置的大小,檢查extent n+2 中是否有未提交事務,如果沒有,則回收extent n+2,本質上,就是在回滾段的鏈表上摘去extent n+2 ,然後繼續檢查extent n+3 決定是否回收,由此重複該動作。Optimal設置決定了回滾段最終回收後的大小,回滾段回縮後大小儘可能的接近optimal設置,如上面例子是4M,可通過下面查詢(shrinks表示回滾段回縮的次數,實際上v$rollstat提供了很多的回滾段信息,大家可以參考oracle document)

SQL> select USN,OPTSIZE,SHRINKS from v$rollstat;



USN OPTSIZE SHRINKS

---------- ---------- ----------

0 0

1 4194304 0

2 4194304 0

3 4194304 0

4 4194304 0

5 4194304 10

6 4194304 0

7 4194304 0

9 0



9 rows selected.



l 系統回滾段與延遲迴滾段
SYSTEM 回滾段是創建在系統表空間中,主要是用於系統級的事務和分配普通事務於其他回滾段上。當手工創建數據庫後需要創建普通回滾段之前必須首先創建系統回滾段。按照oracle文檔說明,當普通事務異常多的事情可能會出現使用系統回滾段的情況。但正常情況下,系統回滾段主要用於兩個方面。一是系統事務,比如針對數據字典的操作的truncate table 和 drop table 。如果truncate table or drop table 的過程中沒有成功,則系統會根據系統回滾段中的數據字典操作信息對該DDL操作進行回退。另一個方面,就是延遲迴滾段(Deferred Rollback Segment)。延遲迴滾段表示的是,當我們使一個表空間OFFLINE(exeample: alter tablespace users offline)之後,由於表空間不可用(不能進行讀寫),這個時候若有事務數據位於該表空間並且執行了回滾命令,回滾完成將顯示給client,對於client看起來該事務已經回滾,但是對於數據庫來說該回滾並沒有真正完成,這個時候數據庫將該回滾信息寫入系統回滾段(這就是延遲迴滾段),等表空間重新ONLINE的時候,數據庫從系統回滾段中將回滾信息寫入表空間。



l 回滾段的設置和管理
事實上,對於作爲個人意見來說,回滾段的管理本不應該是作爲DBA的複雜的任務來對待的,因爲回滾段的管理本來就可以使其很簡單。幾乎所有的系統出現回滾段問題,不外乎都是回滾段大小不足、回滾段個數太少。9i以前的版本因爲對於我們來說,無非也就是這兩個問題。

關於回滾段表空間大小、回滾段數據文件的擴展、回滾段的擴展等創建時指定的參數問題,我想參考創建語法就足夠了,沒有必要在這上去糾纏max extents是100還是200,你會發現去考慮這些參數沒有實質上的意義了。所有的一切設置,我只需要問幾個問題就足夠了:

1:系統併發事務數有多少?

2:系統是否存在大查詢或者大是事務?頻繁麼?

3:能提供給系統的回滾段表空間的磁盤空間是多少?



在初始化參數文件中存在參數transactions_per_rollback_segment和transactions,共同決定了實例啓動的時候將嘗試聯機的最大回滾段個數,transactions決定了同時存在的最大事務數。在這裏順便提及的2個初始化參數

max_rollback_segments 系統允許的最大回滾段個數

rollback_segments 該參數是一個參數列表,假如創建回滾段的時候是PUBLIC類型,則跟該參數無關,假如是PRIVATE類型的,則必須使得回滾段出現在該參數列表裏面,否則數據庫啓動之後這些回滾段不會自動聯機(可手動)。在OPS/RAC中,PUBLIC類型的回滾段表示所有的INSTANCE都可以聯機這些回滾段(但同一時刻只能有一個實例聯機),相當於是一個公共回滾段池。

在實例啓動的時候,實例嘗試聯機rollback_segments中設置的回滾段,直到達到個數爲min(CEIL(transactions/transactions_per_rollback_segment), max_rollback_segments)。若沒有達到這個值,則實例嘗試在PUBLIC類型的回滾段池中嘗試聯機回滾段,直到達到該值或者不再有回滾段可聯機。

當一個實例啓動後其聯機回滾段的個數是否足夠,跟併發事務數有關,若每個回滾段上活動事務過多可能導致嚴重的回滾段爭用。

這裏說了問題一相關內容,我們再看後面兩個問題。由於回滾段的擴展和回收是昂貴代價的操作,通常我們是要避免的。如果存在大的查詢,就算不會去寫回滾段,但是由於一致讀,我們也可以參照前面內容,知道如果這期間事務繁忙回滾段被循環使用覆蓋過,可能出現著名的ORA-01555錯誤。又由於事務產生的時候除非人爲指定使用哪個回滾段,否則事務使用哪個回滾段對於我們應用來說是透明的,同時我們能指定事務使用哪個回滾段但並不能阻止別的事務不使用某個回滾段,這樣我們就必須認識到,回滾段設置成大小不一致是不合適的,幾乎是沒有意義的,因爲瓶頸總是決定於最小的一個回滾段(這類似於木桶原理,決定裝水量的多少是由最短的片所決定的)。所以我們應該統一回滾段的大小。那通常對於一個系統來說,幾百M的磁盤空間甚至幾G的磁盤空間根本不是問題,所以我們沒有理由在這裏研究回滾段到底是使用4M大小還是10M大小,我們根據能提供的磁盤空間的估計,完全可以設置回滾段爲50M/100M甚至更大的大小,這主要決定於在大查詢運行期間每個回滾段上可能的事務生成量,以及單個事務可能產生的回滾數據的大小。假如系統偶爾存在批量作業的時候可能使得某個回滾段擴展到1G,但平常我們的回滾段大小在50M就不會出現回縮現象。那這個特定的時候如果數據庫不繁忙只有大作業我們可以創建幾個很大的回滾段,然後是其他回滾段offline,等批作業完成然後再online其他回滾段,使大回滾段offline。當然可能的話也可以指定批作業使用大的回滾段。或者,我們可以爲所有回滾段設置optimal爲50M,任其特定時刻擴展然後回縮(注意所有回滾段的optimal必須設置一樣大小)。



對於回滾段除了按照我們對系統狀況估計進行創建、刪除外,還有使回滾段聯機和脫機,我們要注意的是如果回滾段處於聯機並且裏面有活動事務的時候,若想使回滾段脫機(offline),則這時回滾段處於一種懸置的狀態,也就是新的事務將不能使用該回滾段,而原有的事務繼續存在,等待回滾段中所有事務完畢後,回滾段成爲脫機狀態。







l 9i的UNDO TABLESPACE
從oracle9i 開始,推薦使用UNDO TABLESPACE,讓系統自動管理回滾段。

SQL> show parameters undo



NAME TYPE VALUE

------------------------------------ ------- -------------

undo_management string AUTO

undo_retention integer 10800

undo_suppress_errors Boolean FALSE

undo_tablespace string UNDOTBS1

SQL>

初始化參數undo_management 決定數據庫使用的回滾段是否使用自動管理模式。AUTO表示自動管理,MANUAL表示手工管理,也就是跟8i中一樣。undo_tablespace指定在自動管理模式下INSTANCE使用哪個表空間,undo_retention表示在自動管理模式下,回滾段中的數據在被覆蓋前保留多長的時間,單位是秒。這個參數應該決定於系統所中一些大查詢運行的時間長度,以避免ORA-01555錯誤。當然,實際上由於9i提供的flashback功能,可根據需要決定該參數設置的時間長度。設置undo_retention的同時要估計這樣長的時間內系統所產生的回滾數據的大小,結合硬件所提供的磁盤空間來綜合考慮。undo_suppress_errors參數如果設置爲true在自動管理模式下,如果我們嘗試在創建回滾段,則不返回錯誤信息,但實際上是無效的,設置爲false則嘗試創建回滾段會返回錯誤信息。

回滾段成爲了自動管理,一方面驗證了前面所說的回滾段的管理的問題本不是一個複雜的問題,另一方面,自動管理讓我們覺得無所適從,幾乎人爲的難以控制它了。比如UNDO表空間變的很大,我們卻不能縮小。這個時候我們可以考慮創建新的UNDO表空間,然後換到新的表空間,這時即使UNDO表空間中有事務也可以切換,只不過不能立即刪除該表空間,切換之後等到原來的表空間中的所有事務處理完畢並且達到undo_retention所限定時間之後,就可以drop原來的UNDO表空間。這樣可以解決UNDO表空間變的太大而無法縮小的問題。命令如下:

SQL> alter system set undo_tablespace = undotbs1;



System altered.



SQL>

這裏要注意若切換了UNDO表空間後應該修改pfile或者spfile使得下次啓動應用新的UNDO表空間。



在自動管理模式下的UNDO表空間中的回滾段的個數是變化的,裏面回滾段依然存在着聯機和脫機的狀況,只不過是系統自己管理。若在脫機的時候回滾段中還存在着活動事務,這時也出現前面所講的一種懸置的狀態。這個時候系統可能會爲此而生成提示信息的trace文件,這是沒有關係的,對系統沒有影響。

在9i下創建非自動管理的回滾段而不使用UNDO 表空間,則設置undo_management爲MANUAL,然後在系統表空間中創建一個回滾段(注意這是必須的),創建自己的回滾段表空間,這時可以在回滾段表空間中創建回滾段,創建完畢刪除系統表空間中的回滾段。

順便提及幾點,UNDO表空間在做含有LOB類型數據的EXP的時候如果數據量過大(也許是超過5G)可能出現BUG,ORACLE9.2.中如果UNDO是ASSM,若設置undo_retention不當等因素導致擴展過大,也會出現BUG,導致系統崩潰只能進行介質恢復。當然,建議管理生產數據庫的DBA們有空多瀏覽metalink,瞭解各種版本的特性和BUG。





l 回滾段著名的ORA-01555問題
關於一致性讀前面已經有介紹,但是這裏我們不得不產生一個疑問,一致讀獲取的時候發現回滾段已經被覆蓋而出現找不着變化前映像,也就是當COMMIT SCN大於T查詢嘗試去回滾段中找回數據卻發現回滾段已經被覆蓋了(因爲回滾段是循環使用的),則會出現著名的ORA-01555錯誤。

另外一種情況是關於塊清除(block cleanout),這涉及到oracle的一個塊清除(block cleanout)的概念,也就是說已經提交的數據,需要標誌爲已經提交,從而使得後面的會話訪問該數據的時候不再產生一致讀而直接讀該塊。而如果事務提交的時候塊已經被寫入磁盤,則當時不會對塊進行清除,需要延遲清除(delay block cleanout)。當被提交但沒有來得及標誌爲提交的塊在下次被會話讀取的時候會話會檢查該塊上最新的事務狀態是否是活動的,如果已經不是活動的則修改事務標誌。這樣做一次後就不再產生不必要的一致讀。但這種情況僅僅出現在:事務很大可能產生這種情況,事務早已提交,回滾段已經被覆蓋,塊中沒有被標記是否提交,而當前查詢 SCN T也比目前回滾段中記錄的最小的SCN小(查詢已經運行較長時間回滾段都已經被覆蓋)。這個時候數據庫不能判定當前查詢的SCN T 與該塊的COMMIT SCN之間的大小關係,於是返回了錯誤。事實上後面這種情況是罕見的,而理解起來也比較困難一些。通常我們可以不考慮這種情況。

當然上面是從數據庫角度來描述,從應用角度來確診這個問題,有幾種可能:

1:查詢執行時間太長。那麼在這個時候我們首先要做的工作就是優化查詢,然後是考慮能否把查詢放在數據庫不繁忙的時候運行,最後纔是考慮加大回滾段。

2:過度頻繁的提交。假如可以成批提交的事務,我們可能是單條提交了,應該考慮對整個處理一起提交,或者說分段提交而不是單條提交。

3:exp的時候使用了consistent = y。這個參數主要是爲了保證在exp的時候使得所有導出來的表在時間點上具有一致性,可避免存在主外鍵關係的表由於不同表時間點的不一致而破壞了數據的完整性。建議該操作在系統空閒的時候進行。

4:由於回滾段回縮導致回滾段還沒有循環使用的情況下就出現了在回滾段中找不着數據的情況,那這隻能是加大回滾段增大optimal設置。



其他諸如回滾段不能擴展等等一目瞭然的原因,不再累述。



l 回滾段的監控和一些有用script
對於回滾段的監控,其實最通常的是查看v$rollstat動態視圖

SQL> desc v$rollstat

Name Null? Type

----------------------------------------- -------- -------------------

USN NUMBER

EXTENTS NUMBER

RSSIZE NUMBER

WRITES NUMBER

XACTS NUMBER

GETS NUMBER

WAITS NUMBER

OPTSIZE NUMBER

HWMSIZE NUMBER

SHRINKS NUMBER

WRAPS NUMBER

EXTENDS NUMBER

AVESHRINK NUMBER

AVEACTIVE NUMBER

STATUS VARCHAR2(15)

CUREXT NUMBER

CURBLK NUMBER



SQL>

在這個view中如果發現SHRINKS很大可以認爲回滾段設置太小或者optimal設置太小,如果是waits太大可以認爲是回滾段的個數顯得少。我認爲經常根據關鍵字搜索http://tahiti.oracle.com是一個很好的習慣,這裏有幾乎所有的基本概念的問題,大量的oracle documents,這些view的信息都可以在這裏查詢,所有關於oracle的基本問題在這裏幾乎都能找着答案。

另外一個幫助我們診斷問題的view



SQL> select * from v$waitstat;



CLASS COUNT TIME

------------------ ---------- ----------

data block 341 0

sort block 0 0

save undo block 0 0

segment header 0 0

save undo header 0 0

free list 0 0

extent map 0 0

bitmap block 0 0

bitmap index block 0 0

unused 0 0

system undo header 0 0

system undo block 0 0

undo header 4 0

undo block 81 0



14 rows selected.



SQL>

從這個view中可以看出回滾段頭和回滾段塊的爭用,如果嚴重也可以考慮增加回滾段個數和增大回滾段大小



現在給出一些有用的script

下面這個script是對於系統中存在着鎖等待的時候查詢到底是什麼session阻塞了別人。(注意在oracle9.2.0版本中提供了dba_blockers表顯示鎖住其他session的session的信息,而dba_waiters則顯示了被鎖住的session的信息)
SQL> select username,

2 v$lock.sid,

3 trunc(id1/power(2,16)) rbs,

4 bitand(id1,to_number('ffff','xxxx'))+0 slot,

5 id2 seq,

6 lmode,

7 request

8 from v$lock,v$session

9 where v$lock.type='TX'

10 and v$lock.sid = v$session.sid

11 and v$session.username = user;



USERNAME SID RBS SLOT SEQ LMODE REQUEST

------------------------------ ---------- ---------- ---------- ---------- ---------- ----------

RAINY 8 7 45 300 0 6

RAINY 13 7 45 300 6 0



從這裏我們可以看到是LMODE=6的阻塞了LMODE=0的session(LMODE=6表示session擁有鎖,鎖的類型是6,表示獨佔)。

在$ORACLE_HOME\RDBMS\ADMIN目錄下有一個名爲utllockt.sql的script,提供了詳細的說明,該script輸出一個很直觀的數據格式。

另外再介紹一個怎樣查詢數據庫當前某個session的事務所使用的回滾段大小

SQL> select b.sid,

2 a.XIDUSN ,

3 a.USED_UBLK

4 from v$transaction a,v$session b

5 where a.addr = b.TADDR;



SID XIDUSN USED_UBLK

---------- ---------- ----------

8 1 3



SQL>



ORACLE9.2.0版本提供的表內容如下, HOLDING_SESSION與WAITING_SESSION均表示SID,可根據v$session結合查詢信息

SQL> desc dba_blockers

Name Null? Type

----------------------- -------- ----------------

HOLDING_SESSION NUMBER



SQL> desc dba_waiters

Name Null? Type

----------------------- -------- ----------------

WAITING_SESSION NUMBER

HOLDING_SESSION NUMBER

LOCK_TYPE VARCHAR2(26)

MODE_HELD VARCHAR2(40)

MODE_REQUESTED VARCHAR2(40)

LOCK_ID1 NUMBER

LOCK_ID2 NUMBER



SQL>



當然,事實上,還可以結合v$session中SQL_ADDRESS、SQL_HASH_VALUE聯合v$sqlarea,從而知道session正在運行什麼sql,通過v$lock、dba_objects、v$locked_object查詢有什麼鎖,鎖住了什麼對象。只要你瞭解了oracle這些view的內容,所謂這些查詢就變成跟普通應用中查詢的需求一樣,解決問題不過是信手拈來的事情。


本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/biti_rainy/archive/2004/07/03/32810.aspx
發佈了187 篇原創文章 · 獲贊 0 · 訪問量 9350
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章