DB2和 Oracle的并發(fā)控制(鎖)的比較
更新時間:2007年04月02日 00:00:00 作者:
1 引言
在關(guān)系數(shù)據(jù)庫(DB2,Oracle,Sybase,Informix和SQL Server)最小的恢復(fù)和交易單位為一個事務(wù)(Transactions),事務(wù)具有ACID(原子性,一致性,隔離性和永久性)特征。關(guān)系數(shù)據(jù)庫為了確保并發(fā)用戶在存取同一數(shù)據(jù)庫對象時的正確性(即無丟失更新、可重復(fù)讀、不讀"臟"數(shù)據(jù),無"幻像"讀),數(shù)據(jù)庫中引入了并發(fā)(鎖)機(jī)制。基本的鎖類型有兩種:排它鎖(Exclusive locks記為X鎖)和共享鎖(Share locks記為S鎖)。
排它鎖:若事務(wù)T對數(shù)據(jù)D加X鎖,則其它任何事務(wù)都不能再對D加任何類型的鎖,直至T釋放D上的X鎖;一般要求在修改數(shù)據(jù)前要向該數(shù)據(jù)加排它鎖,所以排它鎖又稱為寫鎖。
共享鎖:若事務(wù)T對數(shù)據(jù)D加S鎖,則其它事務(wù)只能對D加S鎖,而不能加X鎖,直至T釋放D上的S鎖;一般要求在讀取數(shù)據(jù)前要向該數(shù)據(jù)加共享鎖,所以共享鎖又稱為讀鎖。
2 DB2 多粒度封鎖機(jī)制介紹
2.1 鎖的對象
DB2支持對表空間、表、行和索引加鎖(大型機(jī)上的數(shù)據(jù)庫還可以支持對數(shù)據(jù)頁加鎖)來保證數(shù)據(jù)庫的并發(fā)完整性。不過在考慮用戶應(yīng)用程序的并發(fā)性的問題上,通常并不檢查用于表空間和索引的鎖。該類問題分析的焦點(diǎn)在于表鎖和行鎖。
2.2 鎖的策略
DB2可以只對表進(jìn)行加鎖,也可以對表和表中的行進(jìn)行加鎖。如果只對表進(jìn)行加鎖,則表中所有的行都受到同等程度的影響。如果加鎖的范圍針對于表及下屬的行,則在對表加鎖后,相應(yīng)的數(shù)據(jù)行上還要加鎖。究竟應(yīng)用程序是對表加行鎖還是同時加表鎖和行鎖,是由應(yīng)用程序執(zhí)行的命令和系統(tǒng)的隔離級別確定。
2.2.1 DB2表鎖的模式
DB2在表一級加鎖可以使用以下加鎖方式:
表一:DB2數(shù)據(jù)庫表鎖的模式
下面對幾種表鎖的模式進(jìn)一步加以闡述:
IS、IX、SIX方式用于表一級并需要行鎖配合,他們可以阻止其他應(yīng)用程序?qū)υ摫砑由吓潘i。
• 如果一個應(yīng)用程序獲得某表的IS鎖,該應(yīng)用程序可獲得某一行上的S鎖,用于只讀操作,同時其他應(yīng)用程序也可以讀取該行,或是對表中的其他行進(jìn)行更改。
• 如果一個應(yīng)用程序獲得某表的IX鎖,該應(yīng)用程序可獲得某一行上的X鎖,用于更改操作,同時其他應(yīng)用程序可以讀取或更改表中的其他行。
• 如果一個應(yīng)用程序獲得某表的SIX鎖,該應(yīng)用程序可以獲得某一行上的X鎖,用于更改操作,同時其他應(yīng)用程序只能對表中其他行進(jìn)行只讀操作。
S、U、X和Z方式用于表一級,但并不需要行鎖配合,是比較嚴(yán)格的表加鎖策略。
• 如果一個應(yīng)用程序得到某表的S鎖。該應(yīng)用程序可以讀表中的任何數(shù)據(jù)。同時它允許其他應(yīng)用程序獲得該表上的只讀請求鎖。如果有應(yīng)用程序需要更改讀該表上的數(shù)據(jù),必須等S鎖被釋放。
• 如果一個應(yīng)用程序得到某表的U鎖,該應(yīng)用程序可以讀表中的任何數(shù)據(jù),并最終可以通過獲得表上的X鎖來得到對表中任何數(shù)據(jù)的修改權(quán)。其他應(yīng)用程序只能讀取該表中的數(shù)據(jù)。U鎖與S鎖的區(qū)別主要在于更改的意圖上。U鎖的設(shè)計(jì)主要是為了避免兩個應(yīng)用程序在擁有S鎖的情況下同時申請X鎖而造成死鎖的。
• 如果一個應(yīng)用程序得到某表上的X鎖,該應(yīng)用程序可以讀或修改表中的任何數(shù)據(jù)。其他應(yīng)用程序不能對該表進(jìn)行讀或者更改操作。
• 如果一個應(yīng)用程序得到某表上的Z鎖,該應(yīng)用程序可以讀或修改表中的任何數(shù)據(jù)。其他應(yīng)用程序,包括未提交讀程序都不能對該表進(jìn)行讀或者更改操作。
IN鎖用于表上以允許未提交讀這一概念。
2.2.2 DB2行鎖的模式
除了表鎖之外,DB2還支持以下幾種方式的行鎖。
表二:DB2數(shù)據(jù)庫行鎖的模式
2.2.3 DB2鎖的兼容性
表三:DB2數(shù)據(jù)庫表鎖的相容矩陣
表四:DB2數(shù)據(jù)庫行鎖的相容矩陣
下表是筆者總結(jié)了DB2中各SQL語句產(chǎn)生表鎖的情況(假設(shè)缺省的隔離級別為CS):
2.3 DB2鎖的升級
每個鎖在內(nèi)存中都需要一定的內(nèi)存空間,為了減少鎖需要的內(nèi)存開銷,DB2提供了鎖升級的功能。鎖升級是通過對表加上非意圖性的表鎖,同時釋放行鎖來減少鎖的數(shù)目,從而達(dá)到減少鎖需要的內(nèi)存開銷的目的。鎖升級是由數(shù)據(jù)庫管理器自動完成的,有兩個數(shù)據(jù)庫的配置參數(shù)直接影響鎖升級的處理:
locklist--在一個數(shù)據(jù)庫全局內(nèi)存中用于鎖存儲的內(nèi)存。單位為頁(4K)。
maxlocks--一個應(yīng)用程序允許得到的鎖占用的內(nèi)存所占locklist大小的百分比。
鎖升級會在這兩種情況下被觸發(fā):
• 某個應(yīng)用程序請求的鎖所占用的內(nèi)存空間超出了maxlocks與locklist的乘積大小。這時,數(shù)據(jù)庫管理器將試圖通過為提出鎖請求的應(yīng)用程序申請表鎖,并釋放行鎖來節(jié)省空間。
• 在一個數(shù)據(jù)庫中已被加上的全部鎖所占的內(nèi)存空間超出了locklist定義的大小。這時,數(shù)據(jù)庫管理器也將試圖通過為提出鎖請求的應(yīng)用程序申請表鎖,并釋放行鎖來節(jié)省空間。
• 鎖升級雖然會降低OLTP應(yīng)用程序的并發(fā)性能,但是鎖升級后會釋放鎖占有內(nèi)存并增大可用的鎖的內(nèi)存空間。
鎖升級是有可能會失敗的,比如,現(xiàn)在一個應(yīng)用程序已經(jīng)在一個表上加有IX鎖,表中的某些行上加有X鎖,另一個應(yīng)用程序又來請求表上的IS鎖,以及很多行上的S鎖,由于申請的鎖數(shù)目過多引起鎖的升級。數(shù)據(jù)庫管理器試圖為該應(yīng)用程序申請表上的S鎖來減少所需要的鎖的數(shù)目,但S鎖與表上原有的IX鎖沖突,鎖升級不能成功。
如果鎖升級失敗,引起鎖升級的應(yīng)用程序?qū)⒔拥揭粋€-912的SQLCODE。在鎖升級失敗后,DBA應(yīng)該考慮增加locklist的大小或者增大maxlocks的百分比。同時對編程人員來說可以在程序里對發(fā)生鎖升級后程序回滾后重新提交事務(wù)(例如:if sqlca.sqlcode=-912 then rollback and retry等)。
3 Oracle 多粒度鎖機(jī)制介紹
根據(jù)保護(hù)對象的不同,Oracle數(shù)據(jù)庫鎖可以分為以下幾大類:
(1) DML lock(data locks,數(shù)據(jù)鎖):用于保護(hù)數(shù)據(jù)的完整性;
(2) DDL lock(dictionary locks,字典鎖):用于保護(hù)數(shù)據(jù)庫對象的結(jié)構(gòu)(例如表、視圖、索引的結(jié)構(gòu)定義);
(3) Internal locks 和latches(內(nèi)部鎖與閂):保護(hù)內(nèi)部數(shù)據(jù)庫結(jié)構(gòu);
(4) Distributed locks(分布式鎖):用于OPS(并行服務(wù)器)中;
(5) PCM locks(并行高速緩存管理鎖):用于OPS(并行服務(wù)器)中。
在Oracle中最主要的鎖是DML(也可稱為data locks,數(shù)據(jù)鎖)鎖。從封鎖粒度(封鎖對象的大?。┑慕嵌瓤?,Oracle DML鎖共有兩個層次,即行級鎖和表級鎖。
3.1 Oracle的TX鎖(行級鎖、事務(wù)鎖)
許多對Oracle不太了解的技術(shù)人員可能會以為每一個TX鎖代表一條被封鎖的數(shù)據(jù)行,其實(shí)不然。TX的本義是Transaction(事務(wù)),當(dāng)一個事務(wù)第一次執(zhí)行數(shù)據(jù)更改(Insert、Update、Delete)或使用SELECT… FOR UPDATE語句進(jìn)行查詢時,它即獲得一個TX(事務(wù))鎖,直至該事務(wù)結(jié)束(執(zhí)行COMMIT或ROLLBACK操作)時,該鎖才被釋放。所以,一個TX鎖,可以對應(yīng)多個被該事務(wù)鎖定的數(shù)據(jù)行(在我們用的時候多是啟動一個事務(wù),然后SELECT… FOR UPDATE NOWAIT)。
在Oracle的每行數(shù)據(jù)上,都有一個標(biāo)志位來表示該行數(shù)據(jù)是否被鎖定。Oracle不像DB2那樣,建立一個鏈表來維護(hù)每一行被加鎖的數(shù)據(jù),這樣就大大減小了行級鎖的維護(hù)開銷,也在很大程度上避免了類似DB2使用行級鎖時經(jīng)常發(fā)生的鎖數(shù)量不夠而進(jìn)行鎖升級的情況。數(shù)據(jù)行上的鎖標(biāo)志一旦被置位,就表明該行數(shù)據(jù)被加X鎖,Oracle在數(shù)據(jù)行上沒有S鎖。
3.2 TM鎖(表級鎖)
3.2.1 意向鎖的引出
表是由行組成的,當(dāng)我們向某個表加鎖時,一方面需要檢查該鎖的申請是否與原有的表級鎖相容;另一方面,還要檢查該鎖是否與表中的每一行上的鎖相容。比如一個事務(wù)要在一個表上加S鎖,如果表中的一行已被另外的事務(wù)加了X鎖,那么該鎖的申請也應(yīng)被阻塞。如果表中的數(shù)據(jù)很多,逐行檢查鎖標(biāo)志的開銷將很大,系統(tǒng)的性能將會受到影響。為了解決這個問題,可以在表級引入新的鎖類型來表示其所屬行的加鎖情況,這就引出了"意向鎖"的概念。
意向鎖的含義是如果對一個結(jié)點(diǎn)加意向鎖,則說明該結(jié)點(diǎn)的下層結(jié)點(diǎn)正在被加鎖;對任一結(jié)點(diǎn)加鎖時,必須先對它的上層結(jié)點(diǎn)加意向鎖。如:對表中的任一行加鎖時,必須先對它所在的表加意向鎖,然后再對該行加鎖。這樣一來,事務(wù)對表加鎖時,就不再需要檢查表中每行記錄的鎖標(biāo)志位了,系統(tǒng)效率得以大大提高。
3.2.2 意向鎖的類型
由兩種基本的鎖類型(S鎖、X鎖),可以自然地派生出兩種意向鎖:
意向共享鎖(Intent Share Lock,簡稱IS鎖):如果要對一個數(shù)據(jù)庫對象加S鎖,首先要對其上級結(jié)點(diǎn)加IS鎖,表示它的后裔結(jié)點(diǎn)擬(意向)加S鎖;
意向排它鎖(Intent Exclusive Lock,簡稱IX鎖):如果要對一個數(shù)據(jù)庫對象加X鎖,首先要對其上級結(jié)點(diǎn)加IX鎖,表示它的后裔結(jié)點(diǎn)擬(意向)加X鎖。
另外,基本的鎖類型(S、X)與意向鎖類型(IS、IX)之間還可以組合出新的鎖類型,理論上可以組合出4種,即:S+IS,S+IX,X+IS,X+IX,但稍加分析不難看出,實(shí)際上只有S+IX有新的意義,其它三種組合都沒有使鎖的強(qiáng)度得到提高(即:S+IS=S,X+IS=X,X+IX=X,這里的"="指鎖的強(qiáng)度相同)。所謂鎖的強(qiáng)度是指對其它鎖的排斥程度。
這樣我們又可以引入一種新的鎖的類型:
共享意向排它鎖(Shared Intent Exclusive Lock,簡稱SIX鎖):如果對一個數(shù)據(jù)庫對象加SIX鎖,表示對它加S鎖,再加IX鎖,即SIX=S+IX。例如:事務(wù)對某個表加SIX鎖,則表示該事務(wù)要讀整個表(所以要對該表加S鎖),同時會更新個別行(所以要對該表加IX鎖)。
這樣數(shù)據(jù)庫對象上所加的鎖類型就可能有5種:即S、X、IS、IX、SIX。
具有意向鎖的多粒度封鎖方法中任意事務(wù)T要對一個數(shù)據(jù)庫對象加鎖,必須先對它的上層結(jié)點(diǎn)加意向鎖。申請封鎖時應(yīng)按自上而下的次序進(jìn)行;釋放封鎖時則應(yīng)按自下而上的次序進(jìn)行;具有意向鎖的多粒度封鎖方法提高了系統(tǒng)的并發(fā)度,減少了加鎖和解鎖的開銷。
3.3 Oracle的TM鎖(表級鎖)
Oracle的DML鎖(數(shù)據(jù)鎖)正是采用了上面提到的多粒度封鎖方法,其行級鎖雖然只有一種(即X鎖),但其TM鎖(表級鎖)類型共有5種,分別稱為共享鎖(S鎖)、排它鎖(X鎖)、行級共享鎖(RS鎖)、行級排它鎖(RX鎖)、共享行級排它鎖(SRX鎖),與上面提到的S、X、IS、IX、SIX相對應(yīng)。需要注意的是,由于Oracle在行級只提供X鎖,所以與RS鎖(通過SELECT … FOR UPDATE語句獲得)對應(yīng)的行級鎖也是X鎖(但是該行數(shù)據(jù)實(shí)際上還沒有被修改),這與理論上的IS鎖是有區(qū)別的。鎖的兼容性是指當(dāng)一個應(yīng)用程序在表(行)上加上某種鎖后,其他應(yīng)用程序是否能夠在表(行)上加上相應(yīng)的鎖,如果能夠加上,說明這兩種鎖是兼容的,否則說明這兩種鎖不兼容,不能對同一數(shù)據(jù)對象并發(fā)存取。
下表為Oracle數(shù)據(jù)庫TM鎖的兼容矩陣(Y=Yes,表示兼容的請求; N=No,表示不兼容的請求;-表示沒有加鎖請求):
表五:Oracle數(shù)據(jù)庫TM鎖的相容矩陣
一方面,當(dāng)Oracle執(zhí)行SELECT…FOR UPDATE、INSERT、UPDATE、DELETE等DML語句時,系統(tǒng)自動在所要操作的表上申請表級RS鎖(SELECT…FOR UPDATE)或RX鎖(INSERT、UPDATE、DELETE),當(dāng)表級鎖獲得后,系統(tǒng)再自動申請TX鎖,并將實(shí)際鎖定的數(shù)據(jù)行的鎖標(biāo)志位置位(指向該TX鎖);另一方面,程序或操作人員也可以通過LOCK TABLE語句來指定獲得某種類型的TM鎖。下表是筆者總結(jié)了Oracle中各SQL語句產(chǎn)生TM鎖的情況:
表六:Oracle數(shù)據(jù)庫TM鎖小結(jié)
我們可以看到,通常的DML操作(SELECT…FOR UPDATE、INSERT、UPDATE、DELETE),在表級獲得的只是意向鎖(RS或RX),其真正的封鎖粒度還是在行級;另外,Oracle數(shù)據(jù)庫的一個顯著特點(diǎn)是,在缺省情況下,單純地讀數(shù)據(jù)(SELECT)并不加鎖,Oracle通過回滾段(Rollback segment)來保證用戶不讀"臟"數(shù)據(jù)。這些都提高了系統(tǒng)的并發(fā)程度。
由于意向鎖及數(shù)據(jù)行上鎖標(biāo)志位的引入,減小了Oracle維護(hù)行級鎖的開銷,這些技術(shù)的應(yīng)用使Oracle能夠高效地處理高度并發(fā)的事務(wù)請求。
4 DB2多粒度封鎖機(jī)制的監(jiān)控
在DB2中對鎖進(jìn)行監(jiān)控主要有兩種方式,第一種方式是快照監(jiān)控,第二種是事件監(jiān)控方式。
4.1 快照監(jiān)控方式
當(dāng)使用快照方式進(jìn)行鎖的監(jiān)控前,必須把監(jiān)控鎖的開關(guān)打開,可以從實(shí)例級別和會話級別打開,具體命令如下:
db2 update dbm cfg using dft_mon_lock on(實(shí)例級別)
db2 update monitor switches using lock on(會話級別,推薦使用)
當(dāng)開關(guān)打開后,可以執(zhí)行下列命令來進(jìn)行鎖的監(jiān)控
db2 get snapshot for locks on ebankdb(可以得到當(dāng)前數(shù)據(jù)庫中具體鎖的詳細(xì)信息)
db2 get snapshot for locks on ebankdb
Fri Aug 15 15:26:00 JiNan 2004(紅色為鎖的關(guān)鍵信息)
Database Lock Snapshot
Database name = DEV
Database path = /db2/DEV/db2dev/NODE0000/SQL00001/
Input database alias = DEV
Locks held = 49
Applications currently connected = 38
Agents currently waiting on locks = 6
Snapshot timestamp = 08-15-2003 15:26:00.951134
Application handle = 6
Application ID = *LOCAL.db2dev.030815021007
Sequence number = 0001
Application name = disp+work
Authorization ID = SAPR3
Application status = UOW Waiting
Status change time =
Application code page = 819
Locks held = 0
Total wait time (ms) = 0
Application handle = 97
Application ID = *LOCAL.db2dev.030815060819
Sequence number = 0001
Application name = tp
Authorization ID = SAPR3
Application status = Lock-wait
Status change time = 08-15-2003 15:08:20.302352
Application code page = 819
Locks held = 6
Total wait time (ms) = 1060648
Subsection waiting for lock = 0
ID of agent holding lock = 100
Application ID holding lock = *LOCAL.db2dev.030815061638
Node lock wait occurred on = 0
Lock object type = Row
Lock mode = Exclusive Lock (X)
Lock mode requested = Exclusive Lock (X)
Name of tablespace holding lock = PSAPBTABD
Schema of table holding lock = SAPR3
Name of table holding lock = TPLOGNAMES
Lock wait start timestamp = 08-15-2003 15:08:20.302356
Lock is a result of escalation = NO
List Of Locks
Lock Object Name = 29204
Node number lock is held at = 0
Object Type = Table
Tablespace Name = PSAPBTABD
Table Schema = SAPR3
Table Name = TPLOGNAMES
Mode = IX
Status = Granted
Lock Escalation = NO
db2 get snapshot for database on dbname |grep -i locks(UNIX,LINUX平臺)
Locks held currently = 7
Lock waits = 75
Time database waited on locks (ms) = 82302438
Lock list memory in use (Bytes) = 20016
Deadlocks detected = 0
Lock escalations = 8
Exclusive lock escalations = 8
Agents currently waiting on locks = 0
Lock Timeouts = 20
db2 get snapshot for database on dbname |find /i "locks"(NT平臺)
db2 get snapshot for locks for applications agentid 45(注:45為應(yīng)用程序句柄)
Application handle = 45
Application ID = *LOCAL.db2dev.030815021827
Sequence number = 0001
Application name = tp
Authorization ID = SAPR3
Application status = UOW Waiting
Status change time =
Application code page = 819
Locks held = 7
Total wait time (ms) = 0
List Of Locks
Lock Object Name = 1130185838
Node number lock is held at = 0
Object Type = Key Value
Tablespace Name = PSAPBTABD
Table Schema = SAPR3
Table Name = TPLOGNAMES
Mode = X
Status = Granted
Lock Escalation = NO
Lock Object Name = 14053937
Node number lock is held at = 0
Object Type = Row
Tablespace Name = PSAPBTABD
Table Schema = SAPR3
Table Name = TPLOGNAMES
Mode = X
Status = Granted
Lock Escalation = NO
也可以執(zhí)行下列表函數(shù)(注:在DB2 V8之前只能通過命令,DB2 V8后可以通過表函數(shù),推薦使用表函數(shù)來進(jìn)行鎖的監(jiān)控)
db2 select * from table(snapshot_lock('DBNAME',-1)) as locktable監(jiān)控鎖信息
db2 select * from table(snapshot_lockwait('DBNAME',-1) as lock_wait_table監(jiān)控應(yīng)用程序鎖等待的信息
4.2 事件監(jiān)控方式:
當(dāng)使用事件監(jiān)控器進(jìn)行鎖的監(jiān)控時候,只能監(jiān)控死鎖(死鎖的產(chǎn)生是因?yàn)橛捎阪i請求沖突而不能結(jié)束事務(wù),并且該請求沖突不能夠在本事務(wù)內(nèi)解決。通常是兩個應(yīng)用程序互相持有對方所需要的鎖,在得不到自己所需要的鎖的情況下,也不會釋放現(xiàn)有的鎖)的情況,具體步驟如下:
db2 create event monitor dlock for deadlocks with details write to file '$HOME/dir'
db2 set event monitor dlock state 1
db2evmon -db dbname -evm dlock看具體的死鎖輸出(如下圖)
Deadlocked Connection ...
Deadlock ID: 4
Participant no.: 1
Participant no. holding the lock: 2
Appl Id: G9B58B1E.D4EA.08D387230817
Appl Seq number: 0336
Appl Id of connection holding the lock: G9B58B1E.D573.079237231003
Seq. no. of connection holding the lock: 0126
Lock wait start time: 06/08/2005 08:10:34.219490
Lock Name : 0x000201350000030E0000000052
Lock Attributes : 0x00000000
Release Flags : 0x40000000
Lock Count : 1
Hold Count : 0
Current Mode : NS - Share (and Next Key Share)
Deadlock detection time: 06/08/2005 08:10:39.828792
Table of lock waited on : ORDERS
Schema of lock waited on : DB2INST1
Tablespace of lock waited on : USERSPACE1
Type of lock: Row
Mode of lock: NS - Share (and Next Key Share)
Mode application requested on lock: X - Exclusive
Node lock occured on: 0
Lock object name: 782
Application Handle: 298
Deadlocked Statement:
Type : Dynamic
Operation: Execute
Section : 34
Creator : NULLID
Package : SYSSN300
Cursor : SQL_CURSN300C34
Cursor was blocking: FALSE
Text : UPDATE ORDERS SET TOTALTAX = ?, TOTALSHIPPING = ?,
LOCKED = ?, TOTALTAXSHIPPING = ?, STATUS = ?, FIELD2 = ?, TIMEPLACED = ?,
FIELD3 = ?, CURRENCY = ?, SEQUENCE = ?, TOTALADJUSTMENT = ?, ORMORDER = ?,
SHIPASCOMPLETE = ?, PROVIDERORDERNUM = ?, TOTALPRODUCT = ?, DESCRIPTION = ?,
MEMBER_ID = ?, ORGENTITY_ID = ?, FIELD1 = ?, STOREENT_ID = ?, ORDCHNLTYP_ID = ?,
ADDRESS_ID = ?, LASTUPDATE = ?, COMMENTS = ?, NOTIFICATIONID = ? WHERE ORDERS_ID = ?
List of Locks:
Lock Name : 0x000201350000030E0000000052
Lock Attributes : 0x00000000
Release Flags : 0x40000000
Lock Count : 2
Hold Count : 0
Lock Object Name : 782
Object Type : Row
Tablespace Name : USERSPACE1
Table Schema : DB2INST1
Table Name : ORDERS
Mode : X - Exclusive
Lock Name : 0x00020040000029B30000000052
Lock Attributes : 0x00000020
Release Flags : 0x40000000
Lock Count : 1
Hold Count : 0
Lock Object Name : 10675
Object Type : Row
Tablespace Name : USERSPACE1
Table Schema : DB2INST1
Table Name : BKORDITEM
Mode : X - Exclusive(略去后面信息)
5 Oracle 多粒度封鎖機(jī)制的監(jiān)控
為了監(jiān)控Oracle系統(tǒng)中鎖的狀況,我們需要對幾個系統(tǒng)視圖有所了解:
5.1 v$lock視圖
v$lock視圖列出當(dāng)前系統(tǒng)持有的或正在申請的所有鎖的情況,其主要字段說明如下:
表七:v$lock視圖主要字段說明
其中在TYPE字段的取值中,本文只關(guān)心TM、TX兩種DML鎖類型;
5.2 v$locked_object視圖
v$locked_object視圖列出當(dāng)前系統(tǒng)中哪些對象正被鎖定,其主要字段說明如下:
表八:v$locked_object視圖字段說明
5.3 Oracle鎖監(jiān)控腳本
根據(jù)上述系統(tǒng)視圖,可以編制腳本來監(jiān)控?cái)?shù)據(jù)庫中鎖的狀況。
5.3.1 showlock.sql
第一個腳本showlock.sql,該腳本通過連接v$locked_object與all_objects兩視圖,顯示哪些對象被哪些會話鎖?。?
/* showlock.sql */
column o_name format a10
column lock_type format a20
column object_name format a15
select rpad(oracle_username,10) o_name,session_id sid,
decode(locked_mode,0,'None',1,'Null',2,'Row share',
3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') lock_type,
object_name ,xidusn,xidslot,xidsqn
from v$locked_object,all_objects
where v$locked_object.object_id=all_objects.object_id;
5.3.2 showalllock.sql
第二個腳本showalllock.sql,該腳本主要顯示當(dāng)前所有TM、TX鎖的信息;
/* showalllock.sql */
select sid,type,id1,id2,
decode(lmode,0,'None',1,'Null',2,'Row share',
3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive')
lock_type,request,ctime,block
from v$lock
where TYPE IN('TX','TM');
6 DB2 多粒度封鎖機(jī)制示例
以下示例均運(yùn)行在DB2 UDB中,適用所有數(shù)據(jù)庫版本。首先打開三個命令行窗口(DB2 CLP),其中兩個(以下用SESS#1、SESS#2表示)以db2admin用戶連入數(shù)據(jù)庫,以操作SAMPLE庫中提供的示例表(employee);另一個(以下用SESS#3表示)以db2admin用戶連入數(shù)據(jù)庫,對執(zhí)行的每一種類型的SQL語句監(jiān)控加鎖的情況;希望讀者通過這種方式對每一種類型的SQL語句監(jiān)控加鎖的情況。(因?yàn)槭纠艽?,筆者在此就不做了,建議讀者用類似方法驗(yàn)證加鎖情況)
/home/db2inst1>db2 +c update employee set comm=9999(SESS#1)
/home/db2inst1>db2 +c select * from employee(SESS#2處于lock wait)
/home/db2inst1>db2 +c get snapshot for locks on sample(SESS#3監(jiān)控加鎖情況)
注:db2 +c為不自動提交(commit)SQL語句,也可以通過 db2 update command options using c off關(guān)閉自動提交(autocommit,缺省是自動提交)
7 總結(jié)
總的來說,DB2的鎖和Oracle的鎖主要有以下大的區(qū)別:
1.Oracle通過具有意向鎖的多粒度封鎖機(jī)制進(jìn)行并發(fā)控制,保證數(shù)據(jù)的一致性。其DML鎖(數(shù)據(jù)鎖)分為兩個層次(粒度):即表級和行級。通常的DML操作在表級獲得的只是意向鎖(RS或RX),其真正的封鎖粒度還是在行級;DB2也是通過具有意向鎖的多粒度封鎖機(jī)制進(jìn)行并發(fā)控制,保證數(shù)據(jù)的一致性。其DML鎖(數(shù)據(jù)鎖)分為兩個層次(粒度):即表級和行級。通常的DML操作在表級獲得的只是意向鎖(IS,SIX或IX),其真正的封鎖粒度也是在行級;另外,在Oracle數(shù)據(jù)庫中,單純地讀數(shù)據(jù)(SELECT)并不加鎖,這些都提高了系統(tǒng)的并發(fā)程度,Oracle強(qiáng)調(diào)的是能夠"讀"到數(shù)據(jù),并且能夠快速的進(jìn)行數(shù)據(jù)讀取。而DB2的鎖強(qiáng)調(diào)的是"讀一致性",進(jìn)行讀數(shù)據(jù)(SELECT)時會根據(jù)不同的隔離級別(RR,RS,CS)而分別加S,IS,IS鎖,只有在使用UR隔離級別時才不加鎖。從而保證不同應(yīng)用程序和用戶讀取的數(shù)據(jù)是一致的。
2. 在支持高并發(fā)度的同時,DB2和Oracle對鎖的操縱機(jī)制有所不同:Oracle利用意向鎖及數(shù)據(jù)行上加鎖標(biāo)志位等設(shè)計(jì)技巧,減小了Oracle維護(hù)行級鎖的開銷,使其在數(shù)據(jù)庫并發(fā)控制方面有著一定的優(yōu)勢。而DB2中對每個鎖會在鎖的內(nèi)存(locklist)中申請分配一定字節(jié)的內(nèi)存空間,具體是X鎖64字節(jié)內(nèi)存,S鎖32字節(jié)內(nèi)存(注:DB2 V8之前是X鎖72字節(jié)內(nèi)存而S鎖36字節(jié)內(nèi)存)。
3. Oracle數(shù)據(jù)庫中不存在鎖升級,而DB2數(shù)據(jù)庫中當(dāng)數(shù)據(jù)庫表中行級鎖的使用超過locklist*maxlocks會發(fā)生鎖升級。
4. 在Oracle中當(dāng)一個session對表進(jìn)行insert,update,delete時候,另外一個session仍然可以從Orace回滾段或者還原表空間中讀取該表的前映象(before image); 而在DB2中當(dāng)一個session對表進(jìn)行insert,update,delete時候,另外一個session仍然在讀取該表數(shù)據(jù)時候會處于lock wait狀態(tài),除非使用UR隔離級別可以讀取第一個session的未提交的值;所以O(shè)racle同一時刻不同的session有讀不一致的現(xiàn)象,而DB2在同一時刻所有的session都是"讀一致"的。
8 結(jié)束語
DB2中關(guān)于并發(fā)控制(鎖)的建議
1.正確調(diào)整locklist,maxlocks,dlchktime和locktimeout等和鎖有關(guān)的數(shù)據(jù)庫配置參數(shù)(locktimeout最好不要等于-1)。如果鎖內(nèi)存不足會報(bào)SQL0912錯誤而影響并發(fā)。
2.寫出高效而簡潔的SQL語句(非常重要)。
3.在業(yè)務(wù)邏輯處理完后盡可能快速commit釋放鎖。
4.對引起鎖等待(SQL0911返回碼68)和死鎖(SQL0911返回碼2)的SQL語句創(chuàng)建最合理的索引(非常重要,盡量創(chuàng)建復(fù)合索引和包含索引)。
5.使用 altER TABLE 語句的 LOCKSIZE 參數(shù)控制如何在持久基礎(chǔ)上對某個特定表進(jìn)行鎖定。檢查syscat.tables中l(wèi)ocksize字段,盡量在符合業(yè)務(wù)邏輯的情況下,每個表中該字段為"R"(行級鎖)。
6.根據(jù)業(yè)務(wù)邏輯使用正確的隔離級別(RR,RS,CS和UR)。
7.當(dāng)執(zhí)行大量更新時,更新之前,在整個事務(wù)期間鎖定整個表(使用 SQL LOCK TABLE 語句)。這只使用了一把鎖從而防止其它事務(wù)進(jìn)行這些更新,但是對于其他用戶它的確減少了數(shù)據(jù)并發(fā)性。
在關(guān)系數(shù)據(jù)庫(DB2,Oracle,Sybase,Informix和SQL Server)最小的恢復(fù)和交易單位為一個事務(wù)(Transactions),事務(wù)具有ACID(原子性,一致性,隔離性和永久性)特征。關(guān)系數(shù)據(jù)庫為了確保并發(fā)用戶在存取同一數(shù)據(jù)庫對象時的正確性(即無丟失更新、可重復(fù)讀、不讀"臟"數(shù)據(jù),無"幻像"讀),數(shù)據(jù)庫中引入了并發(fā)(鎖)機(jī)制。基本的鎖類型有兩種:排它鎖(Exclusive locks記為X鎖)和共享鎖(Share locks記為S鎖)。
排它鎖:若事務(wù)T對數(shù)據(jù)D加X鎖,則其它任何事務(wù)都不能再對D加任何類型的鎖,直至T釋放D上的X鎖;一般要求在修改數(shù)據(jù)前要向該數(shù)據(jù)加排它鎖,所以排它鎖又稱為寫鎖。
共享鎖:若事務(wù)T對數(shù)據(jù)D加S鎖,則其它事務(wù)只能對D加S鎖,而不能加X鎖,直至T釋放D上的S鎖;一般要求在讀取數(shù)據(jù)前要向該數(shù)據(jù)加共享鎖,所以共享鎖又稱為讀鎖。
2 DB2 多粒度封鎖機(jī)制介紹
2.1 鎖的對象
DB2支持對表空間、表、行和索引加鎖(大型機(jī)上的數(shù)據(jù)庫還可以支持對數(shù)據(jù)頁加鎖)來保證數(shù)據(jù)庫的并發(fā)完整性。不過在考慮用戶應(yīng)用程序的并發(fā)性的問題上,通常并不檢查用于表空間和索引的鎖。該類問題分析的焦點(diǎn)在于表鎖和行鎖。
2.2 鎖的策略
DB2可以只對表進(jìn)行加鎖,也可以對表和表中的行進(jìn)行加鎖。如果只對表進(jìn)行加鎖,則表中所有的行都受到同等程度的影響。如果加鎖的范圍針對于表及下屬的行,則在對表加鎖后,相應(yīng)的數(shù)據(jù)行上還要加鎖。究竟應(yīng)用程序是對表加行鎖還是同時加表鎖和行鎖,是由應(yīng)用程序執(zhí)行的命令和系統(tǒng)的隔離級別確定。
2.2.1 DB2表鎖的模式
DB2在表一級加鎖可以使用以下加鎖方式:
表一:DB2數(shù)據(jù)庫表鎖的模式
下面對幾種表鎖的模式進(jìn)一步加以闡述:
IS、IX、SIX方式用于表一級并需要行鎖配合,他們可以阻止其他應(yīng)用程序?qū)υ摫砑由吓潘i。
• 如果一個應(yīng)用程序獲得某表的IS鎖,該應(yīng)用程序可獲得某一行上的S鎖,用于只讀操作,同時其他應(yīng)用程序也可以讀取該行,或是對表中的其他行進(jìn)行更改。
• 如果一個應(yīng)用程序獲得某表的IX鎖,該應(yīng)用程序可獲得某一行上的X鎖,用于更改操作,同時其他應(yīng)用程序可以讀取或更改表中的其他行。
• 如果一個應(yīng)用程序獲得某表的SIX鎖,該應(yīng)用程序可以獲得某一行上的X鎖,用于更改操作,同時其他應(yīng)用程序只能對表中其他行進(jìn)行只讀操作。
S、U、X和Z方式用于表一級,但并不需要行鎖配合,是比較嚴(yán)格的表加鎖策略。
• 如果一個應(yīng)用程序得到某表的S鎖。該應(yīng)用程序可以讀表中的任何數(shù)據(jù)。同時它允許其他應(yīng)用程序獲得該表上的只讀請求鎖。如果有應(yīng)用程序需要更改讀該表上的數(shù)據(jù),必須等S鎖被釋放。
• 如果一個應(yīng)用程序得到某表的U鎖,該應(yīng)用程序可以讀表中的任何數(shù)據(jù),并最終可以通過獲得表上的X鎖來得到對表中任何數(shù)據(jù)的修改權(quán)。其他應(yīng)用程序只能讀取該表中的數(shù)據(jù)。U鎖與S鎖的區(qū)別主要在于更改的意圖上。U鎖的設(shè)計(jì)主要是為了避免兩個應(yīng)用程序在擁有S鎖的情況下同時申請X鎖而造成死鎖的。
• 如果一個應(yīng)用程序得到某表上的X鎖,該應(yīng)用程序可以讀或修改表中的任何數(shù)據(jù)。其他應(yīng)用程序不能對該表進(jìn)行讀或者更改操作。
• 如果一個應(yīng)用程序得到某表上的Z鎖,該應(yīng)用程序可以讀或修改表中的任何數(shù)據(jù)。其他應(yīng)用程序,包括未提交讀程序都不能對該表進(jìn)行讀或者更改操作。
IN鎖用于表上以允許未提交讀這一概念。
2.2.2 DB2行鎖的模式
除了表鎖之外,DB2還支持以下幾種方式的行鎖。
表二:DB2數(shù)據(jù)庫行鎖的模式
2.2.3 DB2鎖的兼容性
表三:DB2數(shù)據(jù)庫表鎖的相容矩陣
表四:DB2數(shù)據(jù)庫行鎖的相容矩陣
下表是筆者總結(jié)了DB2中各SQL語句產(chǎn)生表鎖的情況(假設(shè)缺省的隔離級別為CS):
2.3 DB2鎖的升級
每個鎖在內(nèi)存中都需要一定的內(nèi)存空間,為了減少鎖需要的內(nèi)存開銷,DB2提供了鎖升級的功能。鎖升級是通過對表加上非意圖性的表鎖,同時釋放行鎖來減少鎖的數(shù)目,從而達(dá)到減少鎖需要的內(nèi)存開銷的目的。鎖升級是由數(shù)據(jù)庫管理器自動完成的,有兩個數(shù)據(jù)庫的配置參數(shù)直接影響鎖升級的處理:
locklist--在一個數(shù)據(jù)庫全局內(nèi)存中用于鎖存儲的內(nèi)存。單位為頁(4K)。
maxlocks--一個應(yīng)用程序允許得到的鎖占用的內(nèi)存所占locklist大小的百分比。
鎖升級會在這兩種情況下被觸發(fā):
• 某個應(yīng)用程序請求的鎖所占用的內(nèi)存空間超出了maxlocks與locklist的乘積大小。這時,數(shù)據(jù)庫管理器將試圖通過為提出鎖請求的應(yīng)用程序申請表鎖,并釋放行鎖來節(jié)省空間。
• 在一個數(shù)據(jù)庫中已被加上的全部鎖所占的內(nèi)存空間超出了locklist定義的大小。這時,數(shù)據(jù)庫管理器也將試圖通過為提出鎖請求的應(yīng)用程序申請表鎖,并釋放行鎖來節(jié)省空間。
• 鎖升級雖然會降低OLTP應(yīng)用程序的并發(fā)性能,但是鎖升級后會釋放鎖占有內(nèi)存并增大可用的鎖的內(nèi)存空間。
鎖升級是有可能會失敗的,比如,現(xiàn)在一個應(yīng)用程序已經(jīng)在一個表上加有IX鎖,表中的某些行上加有X鎖,另一個應(yīng)用程序又來請求表上的IS鎖,以及很多行上的S鎖,由于申請的鎖數(shù)目過多引起鎖的升級。數(shù)據(jù)庫管理器試圖為該應(yīng)用程序申請表上的S鎖來減少所需要的鎖的數(shù)目,但S鎖與表上原有的IX鎖沖突,鎖升級不能成功。
如果鎖升級失敗,引起鎖升級的應(yīng)用程序?qū)⒔拥揭粋€-912的SQLCODE。在鎖升級失敗后,DBA應(yīng)該考慮增加locklist的大小或者增大maxlocks的百分比。同時對編程人員來說可以在程序里對發(fā)生鎖升級后程序回滾后重新提交事務(wù)(例如:if sqlca.sqlcode=-912 then rollback and retry等)。
3 Oracle 多粒度鎖機(jī)制介紹
根據(jù)保護(hù)對象的不同,Oracle數(shù)據(jù)庫鎖可以分為以下幾大類:
(1) DML lock(data locks,數(shù)據(jù)鎖):用于保護(hù)數(shù)據(jù)的完整性;
(2) DDL lock(dictionary locks,字典鎖):用于保護(hù)數(shù)據(jù)庫對象的結(jié)構(gòu)(例如表、視圖、索引的結(jié)構(gòu)定義);
(3) Internal locks 和latches(內(nèi)部鎖與閂):保護(hù)內(nèi)部數(shù)據(jù)庫結(jié)構(gòu);
(4) Distributed locks(分布式鎖):用于OPS(并行服務(wù)器)中;
(5) PCM locks(并行高速緩存管理鎖):用于OPS(并行服務(wù)器)中。
在Oracle中最主要的鎖是DML(也可稱為data locks,數(shù)據(jù)鎖)鎖。從封鎖粒度(封鎖對象的大?。┑慕嵌瓤?,Oracle DML鎖共有兩個層次,即行級鎖和表級鎖。
3.1 Oracle的TX鎖(行級鎖、事務(wù)鎖)
許多對Oracle不太了解的技術(shù)人員可能會以為每一個TX鎖代表一條被封鎖的數(shù)據(jù)行,其實(shí)不然。TX的本義是Transaction(事務(wù)),當(dāng)一個事務(wù)第一次執(zhí)行數(shù)據(jù)更改(Insert、Update、Delete)或使用SELECT… FOR UPDATE語句進(jìn)行查詢時,它即獲得一個TX(事務(wù))鎖,直至該事務(wù)結(jié)束(執(zhí)行COMMIT或ROLLBACK操作)時,該鎖才被釋放。所以,一個TX鎖,可以對應(yīng)多個被該事務(wù)鎖定的數(shù)據(jù)行(在我們用的時候多是啟動一個事務(wù),然后SELECT… FOR UPDATE NOWAIT)。
在Oracle的每行數(shù)據(jù)上,都有一個標(biāo)志位來表示該行數(shù)據(jù)是否被鎖定。Oracle不像DB2那樣,建立一個鏈表來維護(hù)每一行被加鎖的數(shù)據(jù),這樣就大大減小了行級鎖的維護(hù)開銷,也在很大程度上避免了類似DB2使用行級鎖時經(jīng)常發(fā)生的鎖數(shù)量不夠而進(jìn)行鎖升級的情況。數(shù)據(jù)行上的鎖標(biāo)志一旦被置位,就表明該行數(shù)據(jù)被加X鎖,Oracle在數(shù)據(jù)行上沒有S鎖。
3.2 TM鎖(表級鎖)
3.2.1 意向鎖的引出
表是由行組成的,當(dāng)我們向某個表加鎖時,一方面需要檢查該鎖的申請是否與原有的表級鎖相容;另一方面,還要檢查該鎖是否與表中的每一行上的鎖相容。比如一個事務(wù)要在一個表上加S鎖,如果表中的一行已被另外的事務(wù)加了X鎖,那么該鎖的申請也應(yīng)被阻塞。如果表中的數(shù)據(jù)很多,逐行檢查鎖標(biāo)志的開銷將很大,系統(tǒng)的性能將會受到影響。為了解決這個問題,可以在表級引入新的鎖類型來表示其所屬行的加鎖情況,這就引出了"意向鎖"的概念。
意向鎖的含義是如果對一個結(jié)點(diǎn)加意向鎖,則說明該結(jié)點(diǎn)的下層結(jié)點(diǎn)正在被加鎖;對任一結(jié)點(diǎn)加鎖時,必須先對它的上層結(jié)點(diǎn)加意向鎖。如:對表中的任一行加鎖時,必須先對它所在的表加意向鎖,然后再對該行加鎖。這樣一來,事務(wù)對表加鎖時,就不再需要檢查表中每行記錄的鎖標(biāo)志位了,系統(tǒng)效率得以大大提高。
3.2.2 意向鎖的類型
由兩種基本的鎖類型(S鎖、X鎖),可以自然地派生出兩種意向鎖:
意向共享鎖(Intent Share Lock,簡稱IS鎖):如果要對一個數(shù)據(jù)庫對象加S鎖,首先要對其上級結(jié)點(diǎn)加IS鎖,表示它的后裔結(jié)點(diǎn)擬(意向)加S鎖;
意向排它鎖(Intent Exclusive Lock,簡稱IX鎖):如果要對一個數(shù)據(jù)庫對象加X鎖,首先要對其上級結(jié)點(diǎn)加IX鎖,表示它的后裔結(jié)點(diǎn)擬(意向)加X鎖。
另外,基本的鎖類型(S、X)與意向鎖類型(IS、IX)之間還可以組合出新的鎖類型,理論上可以組合出4種,即:S+IS,S+IX,X+IS,X+IX,但稍加分析不難看出,實(shí)際上只有S+IX有新的意義,其它三種組合都沒有使鎖的強(qiáng)度得到提高(即:S+IS=S,X+IS=X,X+IX=X,這里的"="指鎖的強(qiáng)度相同)。所謂鎖的強(qiáng)度是指對其它鎖的排斥程度。
這樣我們又可以引入一種新的鎖的類型:
共享意向排它鎖(Shared Intent Exclusive Lock,簡稱SIX鎖):如果對一個數(shù)據(jù)庫對象加SIX鎖,表示對它加S鎖,再加IX鎖,即SIX=S+IX。例如:事務(wù)對某個表加SIX鎖,則表示該事務(wù)要讀整個表(所以要對該表加S鎖),同時會更新個別行(所以要對該表加IX鎖)。
這樣數(shù)據(jù)庫對象上所加的鎖類型就可能有5種:即S、X、IS、IX、SIX。
具有意向鎖的多粒度封鎖方法中任意事務(wù)T要對一個數(shù)據(jù)庫對象加鎖,必須先對它的上層結(jié)點(diǎn)加意向鎖。申請封鎖時應(yīng)按自上而下的次序進(jìn)行;釋放封鎖時則應(yīng)按自下而上的次序進(jìn)行;具有意向鎖的多粒度封鎖方法提高了系統(tǒng)的并發(fā)度,減少了加鎖和解鎖的開銷。
3.3 Oracle的TM鎖(表級鎖)
Oracle的DML鎖(數(shù)據(jù)鎖)正是采用了上面提到的多粒度封鎖方法,其行級鎖雖然只有一種(即X鎖),但其TM鎖(表級鎖)類型共有5種,分別稱為共享鎖(S鎖)、排它鎖(X鎖)、行級共享鎖(RS鎖)、行級排它鎖(RX鎖)、共享行級排它鎖(SRX鎖),與上面提到的S、X、IS、IX、SIX相對應(yīng)。需要注意的是,由于Oracle在行級只提供X鎖,所以與RS鎖(通過SELECT … FOR UPDATE語句獲得)對應(yīng)的行級鎖也是X鎖(但是該行數(shù)據(jù)實(shí)際上還沒有被修改),這與理論上的IS鎖是有區(qū)別的。鎖的兼容性是指當(dāng)一個應(yīng)用程序在表(行)上加上某種鎖后,其他應(yīng)用程序是否能夠在表(行)上加上相應(yīng)的鎖,如果能夠加上,說明這兩種鎖是兼容的,否則說明這兩種鎖不兼容,不能對同一數(shù)據(jù)對象并發(fā)存取。
下表為Oracle數(shù)據(jù)庫TM鎖的兼容矩陣(Y=Yes,表示兼容的請求; N=No,表示不兼容的請求;-表示沒有加鎖請求):
表五:Oracle數(shù)據(jù)庫TM鎖的相容矩陣
一方面,當(dāng)Oracle執(zhí)行SELECT…FOR UPDATE、INSERT、UPDATE、DELETE等DML語句時,系統(tǒng)自動在所要操作的表上申請表級RS鎖(SELECT…FOR UPDATE)或RX鎖(INSERT、UPDATE、DELETE),當(dāng)表級鎖獲得后,系統(tǒng)再自動申請TX鎖,并將實(shí)際鎖定的數(shù)據(jù)行的鎖標(biāo)志位置位(指向該TX鎖);另一方面,程序或操作人員也可以通過LOCK TABLE語句來指定獲得某種類型的TM鎖。下表是筆者總結(jié)了Oracle中各SQL語句產(chǎn)生TM鎖的情況:
表六:Oracle數(shù)據(jù)庫TM鎖小結(jié)
我們可以看到,通常的DML操作(SELECT…FOR UPDATE、INSERT、UPDATE、DELETE),在表級獲得的只是意向鎖(RS或RX),其真正的封鎖粒度還是在行級;另外,Oracle數(shù)據(jù)庫的一個顯著特點(diǎn)是,在缺省情況下,單純地讀數(shù)據(jù)(SELECT)并不加鎖,Oracle通過回滾段(Rollback segment)來保證用戶不讀"臟"數(shù)據(jù)。這些都提高了系統(tǒng)的并發(fā)程度。
由于意向鎖及數(shù)據(jù)行上鎖標(biāo)志位的引入,減小了Oracle維護(hù)行級鎖的開銷,這些技術(shù)的應(yīng)用使Oracle能夠高效地處理高度并發(fā)的事務(wù)請求。
4 DB2多粒度封鎖機(jī)制的監(jiān)控
在DB2中對鎖進(jìn)行監(jiān)控主要有兩種方式,第一種方式是快照監(jiān)控,第二種是事件監(jiān)控方式。
4.1 快照監(jiān)控方式
當(dāng)使用快照方式進(jìn)行鎖的監(jiān)控前,必須把監(jiān)控鎖的開關(guān)打開,可以從實(shí)例級別和會話級別打開,具體命令如下:
db2 update dbm cfg using dft_mon_lock on(實(shí)例級別)
db2 update monitor switches using lock on(會話級別,推薦使用)
當(dāng)開關(guān)打開后,可以執(zhí)行下列命令來進(jìn)行鎖的監(jiān)控
db2 get snapshot for locks on ebankdb(可以得到當(dāng)前數(shù)據(jù)庫中具體鎖的詳細(xì)信息)
db2 get snapshot for locks on ebankdb
Fri Aug 15 15:26:00 JiNan 2004(紅色為鎖的關(guān)鍵信息)
Database Lock Snapshot
Database name = DEV
Database path = /db2/DEV/db2dev/NODE0000/SQL00001/
Input database alias = DEV
Locks held = 49
Applications currently connected = 38
Agents currently waiting on locks = 6
Snapshot timestamp = 08-15-2003 15:26:00.951134
Application handle = 6
Application ID = *LOCAL.db2dev.030815021007
Sequence number = 0001
Application name = disp+work
Authorization ID = SAPR3
Application status = UOW Waiting
Status change time =
Application code page = 819
Locks held = 0
Total wait time (ms) = 0
Application handle = 97
Application ID = *LOCAL.db2dev.030815060819
Sequence number = 0001
Application name = tp
Authorization ID = SAPR3
Application status = Lock-wait
Status change time = 08-15-2003 15:08:20.302352
Application code page = 819
Locks held = 6
Total wait time (ms) = 1060648
Subsection waiting for lock = 0
ID of agent holding lock = 100
Application ID holding lock = *LOCAL.db2dev.030815061638
Node lock wait occurred on = 0
Lock object type = Row
Lock mode = Exclusive Lock (X)
Lock mode requested = Exclusive Lock (X)
Name of tablespace holding lock = PSAPBTABD
Schema of table holding lock = SAPR3
Name of table holding lock = TPLOGNAMES
Lock wait start timestamp = 08-15-2003 15:08:20.302356
Lock is a result of escalation = NO
List Of Locks
Lock Object Name = 29204
Node number lock is held at = 0
Object Type = Table
Tablespace Name = PSAPBTABD
Table Schema = SAPR3
Table Name = TPLOGNAMES
Mode = IX
Status = Granted
Lock Escalation = NO
db2 get snapshot for database on dbname |grep -i locks(UNIX,LINUX平臺)
Locks held currently = 7
Lock waits = 75
Time database waited on locks (ms) = 82302438
Lock list memory in use (Bytes) = 20016
Deadlocks detected = 0
Lock escalations = 8
Exclusive lock escalations = 8
Agents currently waiting on locks = 0
Lock Timeouts = 20
db2 get snapshot for database on dbname |find /i "locks"(NT平臺)
db2 get snapshot for locks for applications agentid 45(注:45為應(yīng)用程序句柄)
Application handle = 45
Application ID = *LOCAL.db2dev.030815021827
Sequence number = 0001
Application name = tp
Authorization ID = SAPR3
Application status = UOW Waiting
Status change time =
Application code page = 819
Locks held = 7
Total wait time (ms) = 0
List Of Locks
Lock Object Name = 1130185838
Node number lock is held at = 0
Object Type = Key Value
Tablespace Name = PSAPBTABD
Table Schema = SAPR3
Table Name = TPLOGNAMES
Mode = X
Status = Granted
Lock Escalation = NO
Lock Object Name = 14053937
Node number lock is held at = 0
Object Type = Row
Tablespace Name = PSAPBTABD
Table Schema = SAPR3
Table Name = TPLOGNAMES
Mode = X
Status = Granted
Lock Escalation = NO
也可以執(zhí)行下列表函數(shù)(注:在DB2 V8之前只能通過命令,DB2 V8后可以通過表函數(shù),推薦使用表函數(shù)來進(jìn)行鎖的監(jiān)控)
db2 select * from table(snapshot_lock('DBNAME',-1)) as locktable監(jiān)控鎖信息
db2 select * from table(snapshot_lockwait('DBNAME',-1) as lock_wait_table監(jiān)控應(yīng)用程序鎖等待的信息
4.2 事件監(jiān)控方式:
當(dāng)使用事件監(jiān)控器進(jìn)行鎖的監(jiān)控時候,只能監(jiān)控死鎖(死鎖的產(chǎn)生是因?yàn)橛捎阪i請求沖突而不能結(jié)束事務(wù),并且該請求沖突不能夠在本事務(wù)內(nèi)解決。通常是兩個應(yīng)用程序互相持有對方所需要的鎖,在得不到自己所需要的鎖的情況下,也不會釋放現(xiàn)有的鎖)的情況,具體步驟如下:
db2 create event monitor dlock for deadlocks with details write to file '$HOME/dir'
db2 set event monitor dlock state 1
db2evmon -db dbname -evm dlock看具體的死鎖輸出(如下圖)
Deadlocked Connection ...
Deadlock ID: 4
Participant no.: 1
Participant no. holding the lock: 2
Appl Id: G9B58B1E.D4EA.08D387230817
Appl Seq number: 0336
Appl Id of connection holding the lock: G9B58B1E.D573.079237231003
Seq. no. of connection holding the lock: 0126
Lock wait start time: 06/08/2005 08:10:34.219490
Lock Name : 0x000201350000030E0000000052
Lock Attributes : 0x00000000
Release Flags : 0x40000000
Lock Count : 1
Hold Count : 0
Current Mode : NS - Share (and Next Key Share)
Deadlock detection time: 06/08/2005 08:10:39.828792
Table of lock waited on : ORDERS
Schema of lock waited on : DB2INST1
Tablespace of lock waited on : USERSPACE1
Type of lock: Row
Mode of lock: NS - Share (and Next Key Share)
Mode application requested on lock: X - Exclusive
Node lock occured on: 0
Lock object name: 782
Application Handle: 298
Deadlocked Statement:
Type : Dynamic
Operation: Execute
Section : 34
Creator : NULLID
Package : SYSSN300
Cursor : SQL_CURSN300C34
Cursor was blocking: FALSE
Text : UPDATE ORDERS SET TOTALTAX = ?, TOTALSHIPPING = ?,
LOCKED = ?, TOTALTAXSHIPPING = ?, STATUS = ?, FIELD2 = ?, TIMEPLACED = ?,
FIELD3 = ?, CURRENCY = ?, SEQUENCE = ?, TOTALADJUSTMENT = ?, ORMORDER = ?,
SHIPASCOMPLETE = ?, PROVIDERORDERNUM = ?, TOTALPRODUCT = ?, DESCRIPTION = ?,
MEMBER_ID = ?, ORGENTITY_ID = ?, FIELD1 = ?, STOREENT_ID = ?, ORDCHNLTYP_ID = ?,
ADDRESS_ID = ?, LASTUPDATE = ?, COMMENTS = ?, NOTIFICATIONID = ? WHERE ORDERS_ID = ?
List of Locks:
Lock Name : 0x000201350000030E0000000052
Lock Attributes : 0x00000000
Release Flags : 0x40000000
Lock Count : 2
Hold Count : 0
Lock Object Name : 782
Object Type : Row
Tablespace Name : USERSPACE1
Table Schema : DB2INST1
Table Name : ORDERS
Mode : X - Exclusive
Lock Name : 0x00020040000029B30000000052
Lock Attributes : 0x00000020
Release Flags : 0x40000000
Lock Count : 1
Hold Count : 0
Lock Object Name : 10675
Object Type : Row
Tablespace Name : USERSPACE1
Table Schema : DB2INST1
Table Name : BKORDITEM
Mode : X - Exclusive(略去后面信息)
5 Oracle 多粒度封鎖機(jī)制的監(jiān)控
為了監(jiān)控Oracle系統(tǒng)中鎖的狀況,我們需要對幾個系統(tǒng)視圖有所了解:
5.1 v$lock視圖
v$lock視圖列出當(dāng)前系統(tǒng)持有的或正在申請的所有鎖的情況,其主要字段說明如下:
表七:v$lock視圖主要字段說明
其中在TYPE字段的取值中,本文只關(guān)心TM、TX兩種DML鎖類型;
5.2 v$locked_object視圖
v$locked_object視圖列出當(dāng)前系統(tǒng)中哪些對象正被鎖定,其主要字段說明如下:
表八:v$locked_object視圖字段說明
5.3 Oracle鎖監(jiān)控腳本
根據(jù)上述系統(tǒng)視圖,可以編制腳本來監(jiān)控?cái)?shù)據(jù)庫中鎖的狀況。
5.3.1 showlock.sql
第一個腳本showlock.sql,該腳本通過連接v$locked_object與all_objects兩視圖,顯示哪些對象被哪些會話鎖?。?
/* showlock.sql */
column o_name format a10
column lock_type format a20
column object_name format a15
select rpad(oracle_username,10) o_name,session_id sid,
decode(locked_mode,0,'None',1,'Null',2,'Row share',
3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive') lock_type,
object_name ,xidusn,xidslot,xidsqn
from v$locked_object,all_objects
where v$locked_object.object_id=all_objects.object_id;
5.3.2 showalllock.sql
第二個腳本showalllock.sql,該腳本主要顯示當(dāng)前所有TM、TX鎖的信息;
/* showalllock.sql */
select sid,type,id1,id2,
decode(lmode,0,'None',1,'Null',2,'Row share',
3,'Row Exclusive',4,'Share',5,'Share Row Exclusive',6,'Exclusive')
lock_type,request,ctime,block
from v$lock
where TYPE IN('TX','TM');
6 DB2 多粒度封鎖機(jī)制示例
以下示例均運(yùn)行在DB2 UDB中,適用所有數(shù)據(jù)庫版本。首先打開三個命令行窗口(DB2 CLP),其中兩個(以下用SESS#1、SESS#2表示)以db2admin用戶連入數(shù)據(jù)庫,以操作SAMPLE庫中提供的示例表(employee);另一個(以下用SESS#3表示)以db2admin用戶連入數(shù)據(jù)庫,對執(zhí)行的每一種類型的SQL語句監(jiān)控加鎖的情況;希望讀者通過這種方式對每一種類型的SQL語句監(jiān)控加鎖的情況。(因?yàn)槭纠艽?,筆者在此就不做了,建議讀者用類似方法驗(yàn)證加鎖情況)
/home/db2inst1>db2 +c update employee set comm=9999(SESS#1)
/home/db2inst1>db2 +c select * from employee(SESS#2處于lock wait)
/home/db2inst1>db2 +c get snapshot for locks on sample(SESS#3監(jiān)控加鎖情況)
注:db2 +c為不自動提交(commit)SQL語句,也可以通過 db2 update command options using c off關(guān)閉自動提交(autocommit,缺省是自動提交)
7 總結(jié)
總的來說,DB2的鎖和Oracle的鎖主要有以下大的區(qū)別:
1.Oracle通過具有意向鎖的多粒度封鎖機(jī)制進(jìn)行并發(fā)控制,保證數(shù)據(jù)的一致性。其DML鎖(數(shù)據(jù)鎖)分為兩個層次(粒度):即表級和行級。通常的DML操作在表級獲得的只是意向鎖(RS或RX),其真正的封鎖粒度還是在行級;DB2也是通過具有意向鎖的多粒度封鎖機(jī)制進(jìn)行并發(fā)控制,保證數(shù)據(jù)的一致性。其DML鎖(數(shù)據(jù)鎖)分為兩個層次(粒度):即表級和行級。通常的DML操作在表級獲得的只是意向鎖(IS,SIX或IX),其真正的封鎖粒度也是在行級;另外,在Oracle數(shù)據(jù)庫中,單純地讀數(shù)據(jù)(SELECT)并不加鎖,這些都提高了系統(tǒng)的并發(fā)程度,Oracle強(qiáng)調(diào)的是能夠"讀"到數(shù)據(jù),并且能夠快速的進(jìn)行數(shù)據(jù)讀取。而DB2的鎖強(qiáng)調(diào)的是"讀一致性",進(jìn)行讀數(shù)據(jù)(SELECT)時會根據(jù)不同的隔離級別(RR,RS,CS)而分別加S,IS,IS鎖,只有在使用UR隔離級別時才不加鎖。從而保證不同應(yīng)用程序和用戶讀取的數(shù)據(jù)是一致的。
2. 在支持高并發(fā)度的同時,DB2和Oracle對鎖的操縱機(jī)制有所不同:Oracle利用意向鎖及數(shù)據(jù)行上加鎖標(biāo)志位等設(shè)計(jì)技巧,減小了Oracle維護(hù)行級鎖的開銷,使其在數(shù)據(jù)庫并發(fā)控制方面有著一定的優(yōu)勢。而DB2中對每個鎖會在鎖的內(nèi)存(locklist)中申請分配一定字節(jié)的內(nèi)存空間,具體是X鎖64字節(jié)內(nèi)存,S鎖32字節(jié)內(nèi)存(注:DB2 V8之前是X鎖72字節(jié)內(nèi)存而S鎖36字節(jié)內(nèi)存)。
3. Oracle數(shù)據(jù)庫中不存在鎖升級,而DB2數(shù)據(jù)庫中當(dāng)數(shù)據(jù)庫表中行級鎖的使用超過locklist*maxlocks會發(fā)生鎖升級。
4. 在Oracle中當(dāng)一個session對表進(jìn)行insert,update,delete時候,另外一個session仍然可以從Orace回滾段或者還原表空間中讀取該表的前映象(before image); 而在DB2中當(dāng)一個session對表進(jìn)行insert,update,delete時候,另外一個session仍然在讀取該表數(shù)據(jù)時候會處于lock wait狀態(tài),除非使用UR隔離級別可以讀取第一個session的未提交的值;所以O(shè)racle同一時刻不同的session有讀不一致的現(xiàn)象,而DB2在同一時刻所有的session都是"讀一致"的。
8 結(jié)束語
DB2中關(guān)于并發(fā)控制(鎖)的建議
1.正確調(diào)整locklist,maxlocks,dlchktime和locktimeout等和鎖有關(guān)的數(shù)據(jù)庫配置參數(shù)(locktimeout最好不要等于-1)。如果鎖內(nèi)存不足會報(bào)SQL0912錯誤而影響并發(fā)。
2.寫出高效而簡潔的SQL語句(非常重要)。
3.在業(yè)務(wù)邏輯處理完后盡可能快速commit釋放鎖。
4.對引起鎖等待(SQL0911返回碼68)和死鎖(SQL0911返回碼2)的SQL語句創(chuàng)建最合理的索引(非常重要,盡量創(chuàng)建復(fù)合索引和包含索引)。
5.使用 altER TABLE 語句的 LOCKSIZE 參數(shù)控制如何在持久基礎(chǔ)上對某個特定表進(jìn)行鎖定。檢查syscat.tables中l(wèi)ocksize字段,盡量在符合業(yè)務(wù)邏輯的情況下,每個表中該字段為"R"(行級鎖)。
6.根據(jù)業(yè)務(wù)邏輯使用正確的隔離級別(RR,RS,CS和UR)。
7.當(dāng)執(zhí)行大量更新時,更新之前,在整個事務(wù)期間鎖定整個表(使用 SQL LOCK TABLE 語句)。這只使用了一把鎖從而防止其它事務(wù)進(jìn)行這些更新,但是對于其他用戶它的確減少了數(shù)據(jù)并發(fā)性。
相關(guān)文章
Oracle 自增(auto increment) 或 標(biāo)識字段的建立方法
SQL SERVER 和 ACCESS 以及 MYSQL 中, 都有一種 自增字段, 通常被用來做 主鍵 或 索引鍵, 但是 ORACLE 中,確并沒有提供這種字段類型(實(shí)際并不是一種字段類型) ,但我們確經(jīng)常需要這個功能。2008-11-11ORACLE LATERAL-SQL-INJECTION 個人見解
最近忙啊忙啊的,今天終于有點(diǎn)點(diǎn)時間抽出來看看技術(shù)文章了,最近國外又出了關(guān)于新型ORA注入技術(shù)的PAPER,趕緊測試,主要是出現(xiàn)在SQL語句字符拼 接的時候,DATE類型轉(zhuǎn)換為VARCHAR 以及 NUMBER轉(zhuǎn)換為VARCHAR加入的格式字符出現(xiàn)問題。2008-05-05Oracle下時間轉(zhuǎn)換在幾種語言中的實(shí)現(xiàn)
Oracle下時間轉(zhuǎn)換在幾種語言中的實(shí)現(xiàn)...2007-04-04