9I/10G 11G online index的實現過程分析

wei-xh發表於2012-05-09
[i=s] 本帖最後由 wei-xh 於 2012-5-9 15:42 編輯

ORACLE 的ONLINE 建立索引在很多手冊上被描述為:不阻塞寫的安全操作。但是11G前,ORACLE一直沒能真正做到這一點。
MYSQL ,POSTGRES裡好像也一直沒能實現ORACLE ONLINE的功能,他們的建立都會阻塞寫操作。我們這裡分析下ORACLE ONLINE建立索引的步驟。

9I、10G版本下ONLINE REBUILD建立索引的過程。
建立索引前,開啟如下跟蹤事件,第一個等待事件,可以觀察到鎖的申請情況。第二個等待事件可以觀察到遞迴執行的SQL。

alter session set events '10704 trace name context forever,level 10';
alter session set events '10046 trace name context forever,level 12';

ORACLE ONLINE REBUILD索引的思路就是透過:
索引建立開始時候的資料+MRGEE索引建立過程中的增量來完成整個建立。

索引建立開始時候的資料:透過一致性讀來實現
索引建立過程中的增量:  透過IOT表記錄的變化日誌來實現。

整個過程分為如下幾個步驟:

1.申請表上型別為2的TM鎖。建立IOT表,用來捕獲增量。

CODE:

跟蹤檔案摘要:
*** 2010-07-27 23:07:16.000
ksqcmi: TM,18fe,0 mode=2 timeout=21474836
ksqcmi: returns 0
create table "SYS_JOURNAL_6399" (C0 NUMBER, opcode char(1), partno number, rid rowid, primary key( C0 , rid ))
organization index TABLESPACE "USERS"
CREATE UNIQUE INDEX "SYS_IOT_TOP_6406" on "SYS_JOURNAL_6399"("C0","RID") INDEX ONLY TOPLEVEL TABLESPACE "USERS" NOPARALLEL
建立IOT表的時候,持有的是原表上2的TM鎖。這是個非常低階別的鎖。即使此時,表上有未提交事務,也不會阻塞這個操作,因為DML操作獲得的3型別的TM鎖與2型別的TM鎖具有相容性。

2.將型別為2的鎖轉化為型別為4的TM鎖。為了阻塞後續的DML操作。
ORACLE在ONLIEN建立索引過程中,透過一致性讀取表段+IOT表增量 來完成整個建立。IOT表記錄了,一致性讀取表資料後的發生的所有資料變化。
因此在真正開始一致性複製舊資料之前,需要確保表上沒有事務。
可以設想一下,如果ORACLE不保證表上所有的事務已結束就開始一致性讀取,那麼一致性讀取表資料建立的索引段+IOT表MERGE完成後,就會丟失資料。IOT表只記錄了一致性讀取表資料後的所有資料變化。對於之前的變更不做記錄。

舉個例子:資料塊1的一條記錄做了修改,把A值變為了B值,但是這個事務沒提交,如果ORACLE不等待這個事務結束就開始建立索引,那麼一致性讀取資料塊的內容,讀取到的將是內容A。在建立索引過程中,這個事務提交了,但是這個B並不會進入到IOT表裡,因為這個事務是索引建立開始前開始的,IOT表不記錄。最終索引建立完成後,這個B會丟失。

因此ORACLE在這個步驟裡申請了一個等級稍微高點的TM 4鎖,假如表上存在事務,那麼這個4的TM鎖將不能獲得,因為它與事務的TM 3鎖衝突。持有這個TM 4鎖,還為了阻塞後面的DML操作,為了讓索引重建儘快可以開始。而這個持有的TM 4鎖,經常是我們在ONLINE 建立索引過程中,風險最大的地方。因為這個4鎖一旦獲得不了,它將會阻塞後續的所有的DML操作。

CODE:

跟蹤檔案摘要:
*** 2010-07-27 23:07:16.000
ksqcmi: TM,18fe,0 mode=4 timeout=21474836
WAIT #1: nam='enqueue' ela= 3072242 p1=1414332420 p2=6398 p3=0

3.因為DML操作都獲得的是TM為3的鎖,它跟4 TM鎖不相容,因此一旦可以獲取到型別為4的TM鎖,代表表上事務都已經結束,這個時候,就可以釋放這個TM 4鎖,將鎖降級為型別為2的TM鎖。至此,開始讀取表資料建立索引。需要注意的是,這裡的讀取表資料,是一致性讀取。
建立新索引的時間要依據表的大小。整個過程要做的事情就是一致性讀取表資料+排序

CODE:

跟蹤檔案摘要:
*** 2010-07-27 23:07:41.000
ksqcmi: TM,18fe,0 mode=2 timeout=21474836
ksqcmi: returns 0
4.讀取IOT表上的變更,在新的索引段上進行MERGE.這個過程中會發現IOT表的記錄數逐漸在減少。最終完成時,只剩下未提交事務所修改的記錄保留在IOT表裡。類似如下的情況。由於這些記錄還沒提交,ONLIEN程式就只能等待。

CODE:

select * from SYS_JOURNAL_207626;
C0 OP PARTNO RID
---------- -- ---------- ------------------
11 I 0 D/////AAGAAAe4DAAa
11 I 0 D/////AAGAAAe4DAAb
12 D 0 D/////AAGAAAe4DAAa
12 D 0 D/////AAGAAAe4DAAb
12 D 0 D/////AAGAAAe4DAAc
12 D 0 D/////AAGAAAe4DAAd
5.獲取表上型別為4的TM鎖,等待未提交的事務結束,阻塞後續的事務,以免讓索引重建過程“無限期”的等待。這裡又是一個風險點,因為申請了一個TM 4鎖,會阻塞後面的DML操作。
一旦步驟4裡涉及的變更記錄都已經提交,那麼就會把最終的這批記錄MERGE進新索引裡。最後刪除IOT表。整個過程完畢。

有個疑問,就是在進行MERGE過程中,ORACLE依據什麼判斷IOT表裡那些記錄已經提交,那些沒提交?IOT表裡貌似沒這個欄位。

看來ORACLE 9I、10G所謂的ONLINE其實並不安全,因為裡面有幾個地方,會申請一個TM 4的鎖,這個鎖一旦獲取不了,就會導致DML操作的阻塞。

11G後,這個情況完全變了,ORACLE做到了真正的ONLINE.


11G ONLINE REBUILD建立索引的過程。
1.申請表上型別為2的TM鎖,建立IOT表。
2.建立完IOT表後,如果表上存在事務,那麼會發生等待,不過這個發生的等待是TX事務等待,不是在表上的TM等待了。
3.建立索引程式會被未提交的事務掛起,但是這個時候存在DML操作的話,可以正常進行。但是這些DML操作變更並不會記錄進IOT表裡。

4.如果表上事務都已經提交,那麼進行一致性讀取表上的舊資料的過程,然後對資料排序。例如:如果表上存在3個沒有提交的事務,那麼會先等待事務1,事務1提交後,會等待事務2,事務2提交後,會等待事務3.直到事務3提交,那麼才可以進行下一步。這個過程可以透過觀察 v$session的P1,P2引數來了解,隨著事務的提交,P1,P2的值也會發生變化,P1,P2的值反應了當前等待在哪個事務上。這個過程雖然不會阻塞事務,但是我們不難發現,如果表上事務併發比較大,那麼重建索引的進行就會被延期。知道表上的“那一刻”不存在事務。
5.把IOT表裡的資料在新索引段上進行MERGE,這個過程中,會發現IOT表的資料逐漸減少。最終只剩下沒提交事務的資料。
6.等待IOT表裡未提交的事務進行提交,這個時候後臺會等待TX事務鎖,型別為4.直到所有的事務都已經提交,這個過程才會完成。這個
過程不會阻塞新進的事務,ORACLE會把變更的資料記錄進IOT表裡(當然要涉及到跟索引欄位相關的資料才會被記錄進IOT表裡)。

11G最大的特點是不需要對TM鎖進行鎖轉化了,11G前由於這種鎖轉化,可能會阻塞DML操作,可能會引起故障。

但是理論上11G這種做法也會引起問題,因為在第4、6步,在等待事務結束期間,一直有源源不斷的事務進來,如果運氣差的話,那麼你的索引重建時間就會非常長。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22034023/viewspace-723144/,如需轉載,請註明出處,否則將追究法律責任。

相關文章