日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

Oracle关于TX锁的一个有趣的问题

發(fā)布時(shí)間:2025/3/14 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Oracle关于TX锁的一个有趣的问题 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前陣子有一個(gè)網(wǎng)友在群里問(wèn)了一個(gè)關(guān)于Oracle數(shù)據(jù)庫(kù)的TX鎖問(wèn)題,問(wèn)題原文如下:

?

請(qǐng)教一個(gè)問(wèn)題:?兩個(gè)會(huì)話執(zhí)行不同的delete語(yǔ)句,結(jié)果都是刪除同一個(gè)行。先執(zhí)行的會(huì)話里where條件不加索引走全表掃描,表很大,執(zhí)行很慢;后執(zhí)行的用where條件直接用rowid進(jìn)行delete?Oracle的什么機(jī)制使第二個(gè)會(huì)話執(zhí)行后一直是等待第一個(gè)會(huì)話結(jié)束的呢。

?

那么我們先動(dòng)手實(shí)驗(yàn)一下,來(lái)看看這個(gè)問(wèn)題吧,首先,我們需要一個(gè)數(shù)據(jù)量較大的表(數(shù)據(jù)量大,全表掃描時(shí)間長(zhǎng),方便構(gòu)造實(shí)驗(yàn)效果), 這里實(shí)驗(yàn)測(cè)試的表為INV_TEST,該表在字段FINAL_GARMENT_FACTORY_CD上沒(méi)有索引。因?yàn)槲覀円獦?gòu)造一個(gè)SQL走全表掃描去刪除數(shù)據(jù)。我們更新了兩條記錄,設(shè)置字段FINAL_GARMENT_FACTORY_CD ='KLB'。 如下所示:

?

SQL> SELECT? ROWID, T.FINAL_GARMENT_FACTORY_CD FROM TEST.INV_TEST T WHERE ROWNUM <=10;?ROWID????????????? FINAL_GARM------------------ ----------AAC1coABNAAALEKAAA KLBAAC1coABNAAALEKAAB GEGAAC1coABNAAALEKAAC GEGAAC1coABNAAALEKAAD GEGAAC1coABNAAALEKAAE GEGAAC1coABNAAALEKAAF KLBAAC1coABNAAALEKAAG GEGAAC1coABNAAALEKAAH GEGAAC1coABNAAALEKAAI GEGAAC1coABNAAALEKAAJ GEG

?

首先,在會(huì)話1SID=925)里面執(zhí)行下面SQL語(yǔ)句,刪除FINAL_GARMENT_FACTORY_CD ='KLB'的兩條記錄

?

SQL> SELECT USERENV('SID') FROM DUAL;?USERENV('SID')--------------?????????? 925?SQL> DELETE?FROM TEST.INV_TEST WHERE FINAL_GARMENT_FACTORY_CD ='KLB';

?

在會(huì)話1SID=925)執(zhí)行后,我們?cè)跁?huì)話2SID=197)里面執(zhí)行一個(gè)DELETE語(yǔ)句(刪除ROWID ='AAC1coABNAAALEKAAA'的記錄),其實(shí)就是刪除第一條FINAL_GARMENT_FACTORY_CD ='KLB'的記錄。不過(guò)我們使用的是ROWID這個(gè)條件。

?

?

?SQL> SELECT USERENV('SID') FROM DUAL;???????????????????????????????????? ?USERENV('SID')--------------?????????? 917?SQL> DELETE?FROM TEST.INV_TEST WHERE ROWID ='AAC1coABNAAALEKAAA';

?

?

此時(shí),在會(huì)話3,我們使用下面SQL語(yǔ)句查詢(xún),就會(huì)發(fā)現(xiàn)會(huì)話2SID=917)被會(huì)話1SID=925)阻塞了。

?

?

SQL> COLUMN blockeduser FORMAT a30 SQL> SET linesize 480SQL> BREAK?ON BlockingInst SKIP 1 ON BlockingSid skip 1 ON BlockingSerial SKIP 1 SQL> SELECT?DISTINCT s1.INST_ID???????? BlockingInst, ? 2????????????????? s1.SID???????????? BlockingSid, ? 3????????????????? s1.SERIAL#???????? BlockingSerial, ? 4????????????????? s2.INST_ID???????? BlockedInst, ? 5????????????????? s2.SID???????????? BlockedSid, ? 6????????????????? s2.USERNAME??????? BlockedUser, ? 7????????????????? s2.SECONDS_IN_WAIT BlockedWaitTime ? 8? FROM?? gv$session s1, ? 9???????? gv$lock l1, 10???????? gv$session s2, 11???????? gv$lock l2 12? WHERE? s1.INST_ID = l1.INST_ID 13???????? AND l1.BLOCK IN ( 1, 2 ) 14???????? AND l2.REQUEST != 0 15???????? AND l1.SID = s1.SID 16???????? AND l1.ID1 = l2.ID1 17???????? AND l1.ID2 = l2.ID2 18???????? AND s2.SID = l2.SID 19???????? AND s2.INST_ID = l2.INST_ID 20? ORDER? BY 1, 21??????????? 2, 22??????????? 3 23? / ?BLOCKINGINST BLOCKINGSID BLOCKINGSERIAL BLOCKEDINST BLOCKEDSID BLOCKEDUSER? BLOCKEDWAITTIME------------ ----------- -------------- ----------- ---------- ------------ ---------------?????????? 1???????? 925????????? 11600?????????? 1??????? 917 TEST???????? 30

?

?

SQL> COL SID? FOR 999999;SQL> COL USERNAME FOR A12;SQL> COL MACHINE FOR A40;SQL> COL TYPE FOR A10;SQL> COL OBJECT_NAME FOR A32;SQL> COL LMODE FOR A16;SQL> COL REQUEST FOR A12;SQL> COL BLOCK FOR 999999;SQL> SELECT S.SID???????????????????????????? SID, ? 2???????? S.USERNAME??????????????????????? USERNAME, ? 3???????? S.MACHINE???????????????????????? MACHINE, ? 4???????? L.TYPE??????????????????????????? TYPE, ? 5???????? O.OBJECT_NAME???????????????????? OBJECT_NAME, ? 6???????? DECODE(L.LMODE, 0, 'None', ? 7???????????????????????? 1, 'Null', ? 8???????????????????????? 2, 'Row Share', ? 9???????????????????????? 3, 'Row Exlusive', 10???????????????????????? 4, 'Share', 11???????????????????????? 5, 'Sh/Row Exlusive', 12???????????????????????? 6, 'Exclusive')?? LMODE, 13???????? DECODE(L.REQUEST, 0, 'None', 14?????????????????????????? 1, 'Null', 15?????????????????????????? 2, 'Row Share', 16?????????????????????????? 3, 'Row Exlusive', 17?????????????????????????? 4, 'Share', 18?????????????????????????? 5, 'Sh/Row Exlusive', 19?????????????????????????? 6, 'Exclusive') REQUEST, 20???????? L.BLOCK?????????????????????????? BLOCK 21? FROM?? V$LOCK L, 22???????? V$SESSION S, 23???????? DBA_OBJECTS O 24? WHERE? L.SID = S.SID 25???????? AND USERNAME != 'SYSTEM'? 26???????? AND O.OBJECT_ID(+) = L.ID1; ???? SID USERNAME???? MACHINE??????????????? TYPE?????? OBJECT_NAME????? LMODE??????????? REQUEST?? BLOCK------- ------------ ------------------ ---------- ---------------- ---------------- ------------ -------??? 917 TEST??? DB-Server.localdomain????? TM???????? INV_TEST???????? Row Exlusive???? None????????? 0??? 925 TEST??? DB-Server.localdomain????? TM???????? INV_TEST???????? Row Exlusive???? None????????? 0??? 925 TEST??? DB-Server.localdomain????? TX????????????????????????? Exclusive??????? None????????? 1??? 917 TEST??? DB-Server.localdomain????? TX????????????????????????? None???????????? Exclusive???? 0

?

?

使用下面腳本,我們知道,會(huì)話197ROW_ID=AAC1coABNAAALEKAAA 這條記錄上等待獲取TX鎖,從而導(dǎo)致他被阻塞了。

?

?

COL object_name FOR A32;COL row_id FOR A32;SELECT???? s.p1raw,???? o.owner,???? o.object_name,???? dbms_rowid.rowid_create(1,o.data_object_id,f.relative_fno,s.row_wait_block#,s.row_wait_row#) row_id?FROM???? v$session s???? JOIN dba_objects o ON s.row_wait_obj# = o.object_id???? JOIN dba_segments m ON o.owner = m.owner??????????????????????????? AND o.object_name = m.segment_name???? JOIN dba_data_files f ON s.row_wait_file# = f.file_id????????????????????????????? AND m.tablespace_name = f.tablespace_name?WHERE???? s.event LIKE?'enq: TX%'

?

?

?

?

?

其實(shí)到這里就可以回答之前網(wǎng)友的問(wèn)題了。 其實(shí)很簡(jiǎn)單,就是ORACLE數(shù)據(jù)庫(kù)的鎖機(jī)制實(shí)現(xiàn)的。我們知道TX鎖稱(chēng)為事務(wù)鎖或行級(jí)鎖。當(dāng)Oracle執(zhí)行DML語(yǔ)句時(shí),系統(tǒng)自動(dòng)在所要操作的表上申請(qǐng)TM類(lèi)型的鎖。當(dāng)TM鎖獲得后,系統(tǒng)再自動(dòng)申請(qǐng)TX類(lèi)型的鎖,并將實(shí)際鎖定的數(shù)據(jù)行的鎖標(biāo)志位進(jìn)行置位。

?

在數(shù)據(jù)行上只有X鎖(排他鎖)。在 Oracle數(shù)據(jù)庫(kù)中,當(dāng)一個(gè)事務(wù)首次發(fā)起一個(gè)DML語(yǔ)句時(shí)就獲得一個(gè)TX鎖,該鎖保持到事務(wù)被提交或回滾。當(dāng)兩個(gè)或多個(gè)會(huì)話在表的同一條記錄上執(zhí)行 DML語(yǔ)句時(shí),第一個(gè)會(huì)話在該條記錄上加鎖,其他的會(huì)話處于等待狀態(tài)。當(dāng)?shù)谝粋€(gè)會(huì)話提交后,TX鎖被釋放,其他會(huì)話才可以加鎖。由于第一個(gè)SQL語(yǔ)句的執(zhí)行計(jì)劃走全表掃描,所以導(dǎo)致這個(gè)事務(wù)的時(shí)間很長(zhǎng),會(huì)話2就一直被阻塞,直到第一個(gè)會(huì)話提交或回滾。

?

另外,我們都知道在Oracle中實(shí)現(xiàn)了細(xì)粒度的行鎖row lock,且在ORACLE的內(nèi)部實(shí)現(xiàn)中沒(méi)有使用基于內(nèi)存的行鎖管理器,row lock是依賴(lài)于數(shù)據(jù)塊本身實(shí)現(xiàn)的。換句話說(shuō)判定一行數(shù)據(jù)究竟有沒(méi)有沒(méi)鎖住,要求Server Processpin住相應(yīng)的block buffer并檢查才能夠發(fā)現(xiàn)。所以,對(duì)于會(huì)話1SID=925),我們無(wú)法定位到那些行獲取了TX鎖。這個(gè)可以參考https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9533876300346704362

?

那么問(wèn)題來(lái)了,對(duì)于會(huì)話1SQL走全表掃描,找到FINAL_GARMENT_FACTORY_CD ='KLB'的記錄就會(huì)在對(duì)應(yīng)的數(shù)據(jù)行的鎖標(biāo)志進(jìn)行置位。假如FINAL_GARMENT_FACTORY_CD ='KLB'的記錄位于掃描位置的末端呢? 這個(gè)實(shí)驗(yàn)會(huì)是什么樣的結(jié)果呢?我們用下面SQL找出一些記錄。

?

SELECT ROWID, T.* FROM INV_TEST T WHERE STOCK_DATE > SYSDATE -120

?

然后我們將其中一條記錄使用下面腳本更新。

?

SQL> UPDATE INV_TEST SET FINAL_GARMENT_FACTORY_CD='KLB'?WHERE ROWID='AAC1coAB4AAEuXrAAM';?1 row updated.?SQL> COMMIT;?Commit complete.

?

然后我們接下來(lái)繼續(xù)上面實(shí)驗(yàn), 不過(guò)第二個(gè)SQL是刪除ROWID='AAC1coAB4AAEuXrAAM'這條記錄,我們看看實(shí)驗(yàn)結(jié)果

?

?

SQL> SELECT USERENV('SID') FROM DUAL;?USERENV('SID')--------------?????????? 925?SQL> DELETE?FROM INVSUBMAT.INV_TEST WHERE FINAL_GARMENT_FACTORY_CD ='KLB';

?

?

等了大概10秒左右,我們?cè)跁?huì)話2執(zhí)行第二個(gè)SQL,發(fā)現(xiàn)這個(gè)時(shí)候,這個(gè)SQL2馬上執(zhí)行完成了。跟之前的實(shí)驗(yàn)現(xiàn)象完全不同

?

?

?

其實(shí)出現(xiàn)這樣的現(xiàn)象,是因?yàn)榈诙€(gè)會(huì)話(SID=917)首先獲取了這一行的TX鎖, 而第一個(gè)會(huì)話由于走全表掃描,它還沒(méi)掃描到這條記錄。可以說(shuō)在一個(gè)事務(wù)中,對(duì)記錄持有X鎖是有順序和時(shí)間差的。也就是說(shuō)會(huì)話(SID=917)首先在一行上獲取了TX鎖。

?

?

另外需要注意的是:其實(shí)關(guān)于Oraclerow lockTX鎖,雖然很多時(shí)候我們把 TX lock叫做row lock , 但是實(shí)際上它們是兩回事。row lock是基于數(shù)據(jù)塊實(shí)現(xiàn)的,而TX lock則是通過(guò)內(nèi)存中的ENQUEUE LOCK實(shí)現(xiàn)的.它是一種保護(hù)共享資源的鎖定機(jī)制,一個(gè)排隊(duì)機(jī)制,先進(jìn)先出(FIFO). 關(guān)于這個(gè),這里不展開(kāi)敘說(shuō)。

?

?

?

?

?

轉(zhuǎn)載于:https://www.cnblogs.com/kerrycode/p/10900096.html

總結(jié)

以上是生活随笔為你收集整理的Oracle关于TX锁的一个有趣的问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。