在學習子表的外鍵列上是否添加索引這一塊知識時,建議是要添加索引的,但是這裏我想記錄的是許多資料都提到如果不添加索引,在對主表進行UPDATE、DELETE操作時,會對子表加個全表鎖-TM鎖,但是沒有提到是哪種TM鎖,後來經過搜索資料後,並通過自己的實驗,發現是添加的TM LOCK TYPE=4 Share類型的共享鎖。
這裏提一下這個TM LOCK TYPE 4類型的鎖只會作用在UPDATE、DELETE語句對主表進行操作時,執行完畢後,子表上的這個Share鎖就會消失,而不是作用在整個事務上的鎖,所以如果不進行特定的測試,是看不到該鎖的,有請多同學對這一塊理解的有誤,以爲是作用在整個事務上的,即以爲UPDATE、DELETE語句執行完後,會在V$LOCK中看到這個TM LOCK TYPE 4類型的鎖,但是當UPDATE、DELETE語句執行完後,子表上的這個鎖就消失了。
並且在主表上的INSERT語句是不會對子表產生該鎖的。
下面把如何看到該鎖的實驗貼出來,分享給大家:
實驗環境:
數據庫版本:11.2.0.1
操作系統:Windows
下面是實驗記錄可以看到該鎖:
SESSION 1: select sid from v$mystat where rownum=1; SID=17
SESSION 2: select sid from v$mystat where rownum=1; SID=22
使用SCOTT用戶下的表: 主表:DEPT (主鍵DEPTNO,OBJECT_ID=79188) 子表:EMP(外鍵DEPTNO,OBJECT_ID=80523),這裏同學們也可以自己來創建主表和子表。
在子表EMP的DEPTNO列上沒有創建索引時:
SESSION 1:
- 刪除子表上的一行,其實做這步的目的就是爲了一會阻塞主表上的這個Share鎖,這一步是關鍵,否則會看不到這個Share鎖,原因上面已經說過了:
- SQL> delete from emp where rownum=1;
- 1 row deleted.
查看會話中目前已經有的鎖,當對子表進行INSERT、UPDATE、DELETE操作時,也會對主表加個3級的Row-X (SX)行級排它鎖
- SQL> select * from v$lock where sid in (17,22) and type in ('TM','TX') order by sid,type;
- ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
- -------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
- 0D79C52C 0D79C55C 17 TM 79188 0 3 0 6 0
- 0D79C52C 0D79C55C 17 TM 80523 0 3 0 6 0
- 2DE15208 2DE15248 17 TX 196614 3830 6 0 6 0
SESSION 2:
- 我們對主表DELETE或UPDATE一條記錄,這裏要更新或刪除子表中沒有使用的記錄:
- SQL> delete from dept where deptno=50;
- 你會發現上現這條語句hang住了
SESSION 1:
- 查看鎖信息,你會發現22號會話想對80523對象(EMP表)加一個TYPE 4類型的鎖,根據TM鎖兼容的矩陣圖,可以瞭解到3號與4號鎖不兼容,所以22號會話被阻塞,需要等待:
- SQL> select * from v$lock where sid in (17,22) and type in ('TM','TX') order by sid,type;
- ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
- -------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
- 0D79C52C 0D79C55C 17 TM 79188 0 3 0 6 0
- 0D79C52C 0D79C55C 17 TM 80523 0 3 0 6 1
- 2DE15208 2DE15248 17 TX 196614 3830 6 0 6 0
- 0D79C52C 0D79C55C 22 TM 80523 0 0 4 3 0
- 0D79C52C 0D79C55C 22 TM 79188 0 3 0 3 0
- SQL> rollback;
- Rollback complete.
- 回滾後22話會話操作成功,再次查看鎖信息,你會發現子表的4號鎖已經沒有了,所以驗證了上面說的,只在語句操作期間加鎖,操作完成後,就沒了,不作用在整個事務上:
- SQL> select * from v$lock where sid in (17,22) and type in ('TM','TX') order by sid,type;
- ADDR KADDR SID TY ID1 ID2 LMODE REQUEST CTIME BLOCK
- -------- -------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
- 0D79C52C 0D79C55C 22 TM 79188 0 3 0 724 0
- 2DDE31F4 2DDE3234 22 TX 589836 3809 6 0 47 0
上面我們還說過INSERT對主表操作,是不會對子表加鎖的,可以按照上面的操作來一次,這裏就不在演示,如果添加索引後,就不會發生這種阻塞,請自行驗證。
再提一句,如果子表不能被加上類型4的鎖,即上面SESSION 2被阻塞後,再有其它會話來更新子表(UPDATE/DELETE)也會被HANG住。
附上TM鎖兼容矩陣圖: