ORACLE中死鎖的知識點總結

 

死鎖的概念html

 

    什麼是死鎖呢? 其實咱們生活中也有不少相似死鎖的例子。 我先舉一個生活中的例子:過年回家,父親買了一把水彈槍,兒子和侄子爭搶着要先玩,誰也不讓誰,拆開包裝後,一個搶了槍, 一個逮住了子彈和彈夾。兩個都爭着要先玩,可是都各執己見。結果兩我的都玩不了。若是兒子要先玩,就必須讓侄子把子彈和彈夾給他,若是侄子要先玩,就必須讓兒子把槍給侄子。他們就這樣對峙了十幾分鍾,各執己見。 我出來調停,讓兒子把槍先給侄子玩,每一個人玩十分鐘。而後兩我的開開心心一塊兒玩起來。其實這就是一個活生生的死鎖(Dead Lock)的例子。sql

 

   咱們再來看看數據庫死鎖的概念, 所謂死鎖,是指兩個會話,每一個會話都持有另一個會話想要的資源,因爭奪資源而形成的一種互相等待的現象,此時就會出現死鎖,若無外力做用,它們都將沒法推動下去。此時稱系統處於死鎖狀態或系統產生了死鎖,這些永遠在互相等待的進程稱爲死鎖進程。Oracle對於死鎖採起的策略是回滾其中一個事務,讓另一個事務順利進行。數據庫

 

   英文關於deadlock的概念以下:session

 

A deadlock occurs when a session (A) wants a resource held by another session (B) , but that session also wants a resource held by the first session (A). There can be more than 2 sessions involved but the idea is the same.併發

 

   

死鎖的模擬oracle

 

 

   上面瞭解了死鎖的概念,接下來,咱們先人工構造一個簡單的死鎖(Dead Lock)案例來加深理解一下死鎖(Dead Lock),以下所示,咱們先準備測試案例使用的表和數據,測試環境爲Oracle Database 10g Release 10.2.0.5.0 app

 

SQL> create table dead_lock_test( id number(10), name varchar2(32));
 
Table created.
 
SQL> insert into dead_lock_test values(101, 'kerry');
 
1 row created.
 
SQL> insert into dead_lock_test values(102, 'ken');
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> 

 

 

在會話1SID788)中執行下面SQL語句:dom

 

 

SQL> show user;
USER is "TEST"
SQL> select * from v$mystat where rownum=1; 
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       788          0          1
 
SQL> update dead_lock_test set name='kerry1_101' where id=101;
 
1 row updated.
 
SQL> 

 

clip_image001

 

 

 

而後在會話2SID770)中執行下面SQL語句:ide

 

SQL> show user;
USER 爲 "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       770          0          1
 
SQL> update dead_lock_test set name='kerry2_102' where id=102;
 
已更新 1 行。
 
SQL> update dead_lock_test set name='kerry2_101' where id=101;

 

 

 

clip_image002

 

如上所示,會話2SID770)更新id=101這條記錄時,會話被阻塞了。而後咱們在會話1SID788)中執行下面SQL語句:函數

 

SQL>  update dead_lock_test set name='kerry1_102' where id=102;

 

clip_image003

 

此時你會立馬看到會話2SID770)出現ORA-00060錯誤,以下所示:

 

clip_image004

 

 

若是對上面的操做過程的流程有點不直觀,那麼能夠參下面表格:

 

 

image

     

 

固然,若是你如下面這樣的順序更新,那麼會話1就會出現ORA-0060的錯誤,會話1會被當作犧牲的會話進行回滾。

 

 

image

 

                                

 

 

此時在告警日誌中就會出現trc文件。注意RAC環境和單機環境稍有不一樣。在RAC環境中,是由LMDLock Manager Daemon)進程統一管理各個節點之間的鎖資源的,因此,RAC環境中trace文件是由LMD進程來生成的。

 

Tue Mar 28 15:36:30 CST 2017

ORA-00060: Deadlock detected. More info in file /u01/app/oracle/admin/SCM2/bdump/scm2_s000_15815.trc

 

trace文件的部份內容以下所示:

 

*** 2017-03-28 15:36:30.917
*** ACTION NAME:() 2017-03-28 15:36:30.917
*** MODULE NAME:(SQL*Plus) 2017-03-28 15:36:30.917
*** SERVICE NAME:(SCM2) 2017-03-28 15:36:30.917
*** SESSION ID:(770.8) 2017-03-28 15:36:30.917
DEADLOCK DETECTED ( ORA-00060 )
[Transaction Deadlock]
The following deadlock is not an ORACLE error. It is a
deadlock due to user error in the design of an application
or from issuing incorrect ad-hoc SQL. The following
information may aid in determining the deadlock:
Deadlock graph:
                       ---------Blocker(s)--------  ---------Waiter(s)---------
Resource Name          process session holds waits  process session holds waits
TX-0006002e-001e409f        15     770     X             16     788           X
TX-0007002c-001f6346        16     788     X             15     770           X
session 770: DID 0001-0010-00000002     session 788: DID 0001-000F-00000001
session 788: DID 0001-000F-00000001     session 770: DID 0001-0010-00000002
Rows waited on:
Session 788: obj - rowid = 00094900 - AACUkAABEAACLUeAAB
  (dictionary objn - 608512, file - 68, block - 570654, slot - 1)
Session 770: obj - rowid = 00094900 - AACUkAABEAACLUeAAA
  (dictionary objn - 608512, file - 68, block - 570654, slot - 0)
Information on the OTHER waiting sessions:
Session 788:
  sid: 788 ser: 9 audsid: 201878652 user: 132/TEST
    flags: (0xe1) USR/- flags_idl: (0x1) BSY/-/-/-/-/-
    flags2: (0x8)
  pid: 16 O/S info: user: oracle, term: UNKNOWN, ospid: 15817
    image: oracle@getlnx14uat.xxxx.com (S001)
  O/S info: user: oracle, term: pts/2, ospid: 23047, machine: DB-Server.localdomain
            program: sqlplus@DB-Server.localdomain (TNS V1-V3)
  application name: SQL*Plus, hash value=3669949024
  Current SQL Statement:
  update dead_lock_test set name='kerry1_102' where id=102
End of information on OTHER waiting sessions.
Current SQL statement for this session:
update dead_lock_test set name='kerry2_101' where id=101
===================================================

 

 

死鎖的檢測

 

關於死鎖的檢測,對於單實例來講,基本上秒級完成,對於RAC環境,Oracle 10g基本上是1分鐘, Oracle 11g10秒,這個是經過隱含參數_lm_dd_interval控制的。這個參數能夠修改,可是不建議修改。

 

COL NAME FOR A32;
COL KSPPDESC FOR A32;
COL KSPPSTVL FOR A32;
SELECT A.INDX,
        A.KSPPINM NAME,
        A.KSPPDESC,
       B.KSPPSTVL
FROM   X$KSPPI  A,
        X$KSPPCV B
WHERE  A.INDX = B.INDX
     AND LOWER(A.KSPPINM) LIKE  LOWER('%&PARAMETER%');

 

clip_image005

 

clip_image006

 

 

 

 

死鎖的分析(DeadLock Troubleshooting)

 

 

以上面的例子來講,數據庫一旦出現死鎖,立馬會在告警日誌裏面生成這樣一條記錄ORA-00060: Deadlock detected. More info in file xxxxx,那麼從trc文件能分析出什麼信息呢? 下面咱們以上面的例子來簡單分析一下

 

clip_image007

 

其實trc文件裏面最重要、最有用的信息是Deadlock graph。從這部分,咱們能夠分析獲得下面一些有用信息:

 

 

1: 產生死鎖的兩個會話信息

 

 

Deadlock graph:

                       ---------Blocker(s)--------  ---------Waiter(s)---------

Resource Name          process session holds waits  process session holds waits

TX-0006002e-001e409f        15     770     X             16     788           X

TX-0007002c-001f6346        16     788     X             15     770           X

session 770: DID 0001-0010-00000002     session 788: DID 0001-000F-00000001

session 788: DID 0001-000F-00000001     session 770: DID 0001-0010-00000002

 

從上面能夠看到Blockers)Waiters)的相關信息

 

Resource Name   被持有或等待的鎖資源名字

          鎖資源名字由三部分組成 Type-ID1-ID2ID1ID2表明的意思由鎖類型決定。

         具體能夠參考v$lock_type

process   :  V$PROCESS.PID

session   :  V$SESSION.SID

holds    :  鎖持有的模式(Mode the lock is held in

waits    :  鎖等待的模式(Mode the lock is requested in (waiting for)

 

解讀以上死鎖的案例:

 

SID 770 (Process 15) 以排它模式持有鎖:TX-0006002e-001e409f ,以排它模式請求鎖:TX-0007002c-001f6346

SID 788 (Process 16) 以排它模式持有鎖:TX-0007002c-001f6346 ,以排它模式請求鎖:TX-0006002e-001e409f

 

這一段能夠看到,778 阻塞了770, 而後770又阻塞了778 恰好構成了死鎖的條件。這裏要看生成的記錄是兩行仍是一行,是TX仍是TM,若是隻有一行那麼說明是同一個SESSION,多是自治事務引發的死鎖。

 

 

2:死鎖發生在那個對象?

 

Rows waited on:

Session 788: obj - rowid = 00094900 - AACUkAABEAACLUeAAB

  (dictionary objn - 608512, file - 68, block - 570654, slot - 1)

Session 770: obj - rowid = 00094900 - AACUkAABEAACLUeAAA

  (dictionary objn - 608512, file - 68, block - 570654, slot - 0)

 

clip_image008

 

 

3:會話的的機器、應用程序等信息

 

Session 788:

  sid: 788 ser: 9 audsid: 201878652 user: 132/TEST

    flags: (0xe1) USR/- flags_idl: (0x1) BSY/-/-/-/-/-

    flags2: (0x8)

  pid: 16 O/S info: user: oracle, term: UNKNOWN, ospid: 15817

    image: oracle@xxxxxx.xxxx.com (S001)

  O/S info: user: oracle, term: pts/2, ospid: 23047, machine: DB-Server.localdomain

            program: sqlplus@DB-Server.localdomain (TNS V1-V3)

  application name: SQL*Plus, hash value=3669949024

  Current SQL Statement:

  update dead_lock_test set name='kerry1_102' where id=102

End of information on OTHER waiting sessions.

Current SQL statement for this session:

update dead_lock_test set name='kerry2_101' where id=101

 

從上面咱們能夠看到會話788是從機器DB-Server.localdomain上的SQL*Plus應用程序發出的SQL,若是是正式環境,你會看到相關的機器和應用程序名稱。這個會話最後執行的SQL語句爲update dead_lock_test set name='kerry1_102' where id=102

另一個會話執行的最後語句爲update dead_lock_test set name='kerry2_101' where id=101,可是如何找到對應的機器、應用程序信息呢?

 

以下截圖所示,咱們在PROCESS STATE部分,找到對應的SID 770的事務,能夠看到usertermmachineprogram信息。剩下的事情,就是你和開發人員分析腳本,縷清細節,而後如何避免死鎖的問題。

 

clip_image009

 

 

 

 

死鎖的分類

 

死鎖如何分類呢?在Metalink上這篇文章中"How to Identify ORA-00060 Deadlock Types Using Deadlock Graphs in Trace (文檔 ID 1507093.1)"有關於死鎖的分類:以下所示:

 

 

"Key Signature"

Lock Type

Requested
Lock Mode

Deadlock Graph

Likely
Deadlock Type

Comments

Type TX Lock Requesting Mode X (6)

TX

X(6)

TX X X
TX
 
X X

Application

TX Lock Held in Mode X (6) Requesting Mode X (6)

Type TM Lock Requesting Mode SSX (5)

TM

SSX (5)

TM SX SSX SX SSX
TM
 SX SSX 
SX SSX

Missing Index on Foreign Key (FK) Constraint

TM  Lock Held in Mode SX (3) Held SSX (5) Requested

Type TX Lock Requesting Mode S(4)

TX

S(4)

TX X S
TX
 
X S

Insufficient Interested Transaction List (ITL) Provision
OR
Bitmap Index
OR
PK/UK Index

TX Lock Held in Mode X (6) Requesting Mode S (4)

ITL, Bitmap Index and PK/UK Index Signatures are the Same. Further Investigation will be required to identify absolute cause

Type TX Lock Requesting Mode X (6)
Single Row in Deadlock Graph

TX

X(6)

TX X X
Single Row in Deadlock Graph

Self Deadlock
OR
Autonomous Transaction Self Deadlock

This looks the same as a standard application deadlock except that there is only a single row in the deadlock graph.

Type UL Lock in Deadlock Graph

UL

ANY

UL ? ?
?

Application Deadlock Featuring User Defined Locks

This is very similar to the standard application deadlock except that it features User Defined Locks

 

 

 

 

李華榮這篇博客Oracle死鎖(DeadLock)的分類及其模擬裏面對死鎖進行了一個分類,我的以爲是一個通俗、很讚的一個死鎖分類。本文不少地方也是參考、借鑑他博客的內容。

 

 

clip_image011

 

 

 

那麼咱們接下來看看這些死鎖產生的場景,並進行一些分析,不少知識點都是參考Metalink上的一些知識點。

 

 

 

 

1:應用程序死鎖(Application Deadlock

 

 

其實最上面那個死鎖的例子,就屬於Application Deadlock,這個Application Deadlock是發生在同一個表,下面咱們介紹一下Application Deadlock發生在兩個表之間不一樣順序相互更新操做引發的死鎖。下面開始咱們的實驗。建立兩個測試表,並初始化數據。

 

 

SQL> select * from v$version;       
 
BANNER
----------------------------------------------------------------
Oracle Database 10g Release 10.2.0.5.0 - 64bit Production
PL/SQL Release 10.2.0.5.0 - Production
CORE    10.2.0.5.0      Production
TNS for Linux: Version 10.2.0.5.0 - Production
NLSRTL Version 10.2.0.5.0 - Production
 
SQL> create table lock_test_one(name varchar(32));
 
Table created.
 
SQL> create table lock_test_two(name varchar(32));
 
Table created.
 
SQL> insert into lock_test_one values('aaaaaaaa');
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> insert into lock_test_two values('bbbbbbbb');
 
1 row created.
 
SQL> commit;
 
Commit complete.

 

在會話1SID=685)裏更新lock_test_one的記錄,可是不提交更新(下面是一個模擬死鎖出現的過程)

 

 

SQL> show user;
USER is "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       685          0          1
 
SQL> update lock_test_one set name='cccccccc' where name='aaaaaaaa';
 
1 row updated.

 

 

在會話2(SID=719)裏面更新lock_test_two的記錄,也不提交更新:

 

 

SQL> show user;
USER 爲 "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       719          0          1
 
SQL> update lock_test_two set name='dddddddd' where name='bbbbbbbb';
 
已更新 1 行。

 

 

接下來在會話1SID=685)裏面更新lock_test_two,你會發現會話1被回話2阻塞了(開啓另一個會話查詢,就會發現阻塞信息,以下截圖所示)

 

 

SQL> update lock_test_two set name='eeeeeeee' where name='bbbbbbbb';

 

 

clip_image012

 

 

接下來在會話2裏面更新lock_test_one, 模擬死鎖就會出現了

 

 

SQL> update lock_test_one set name='ffffffff' where name='aaaaaaaa';

 

 

 

最後,在會話2(SID=719)裏面執行上面語句後,你會發現會話1當即就會出現ORA-00060的死鎖錯誤信息。

 

 

clip_image013

 

 

 

 

那麼接下來咱們來分析一下死鎖日誌,以下所示,死鎖有兩行記錄,發生在兩個會話之間,能夠判斷爲Application Deadlock. objn的值來看,

 

有兩個值,意味着兩個表之間不一樣順序相互更新操做引發了死鎖,典型的應用程序死鎖有下面特徵:

 

    1Deadlock graph中的記錄多於1行。

    2Deadlock graph中至少有一行鎖類型是TX-X-X

 

clip_image014

 

SQL> col object_name for a32;
SQL> col object_type for a32;
SQL> select object_name, object_type from dba_objects
  2  where object_id=608789;
 
OBJECT_NAME                      OBJECT_TYPE
-------------------------------- --------------------------------
LOCK_TEST_ONE                    TABLE
 
SQL> select object_name, object_type from dba_objects
  2  where object_id=608790;
 
OBJECT_NAME                      OBJECT_TYPE
-------------------------------- --------------------------------
LOCK_TEST_TWO                    TABLE
 
SQL> 

 

還有其它一些有用的信息,例如你想知道死鎖發生在哪一行,那麼能夠經過rowid等位到死鎖發生在哪一行。

 

 

 

Rows waited on:

Session 719: obj - rowid = 00094A15 - AACUoVABEAACLUnAAB

  (dictionary objn - 608789, file - 68, block - 570663, slot - 1)

Session 685: obj - rowid = 00094A16 - AACUoWABEAACLUvAAA

  (dictionary objn - 608790, file - 68, block - 570671, slot - 0)

 

 

 

SQL> select * from lock_test_one where rowid='AACUoVABEAACLUnAAB';
 
NAME
--------------------------------
cccccccc
 
SQL> select * from lock_test_two where rowid='AACUoWABEAACLUvAAA';
 
NAME
--------------------------------
bbbbbbbb

 

 

  clip_image015

 

 

 

2:缺乏外鍵索引引發的死鎖。

 

 

建立表dead_lock_parentdead_lock_foreign,二者存在主外鍵關係,分佈插入兩條測試數據: 

 

 

SQL> create table dead_lock_parent( id number primary key, name varchar2(32));
 
Table created.
 
SQL> create table dead_lock_foreign(fid  number, fname varchar2(32), foreign key(fid) references dead_lock_parent);
 
Table created.
 
SQL> insert into dead_lock_parent values( 1, 'kerry');
 
1 row created.
 
SQL> insert into dead_lock_foreign values(1, 'kerry_fk');  
 
1 row created.
 
SQL> insert into dead_lock_parent values(2, 'jimmy');
 
1 row created.
 
SQL> insert into dead_lock_foreign values(2, 'jimmy_fk');
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> 

 

1:在會話1(會話ID789)裏面執行下面SQL語句:

 

 

 

SQL> show user;
USER 爲 "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       789          0          1
 
SQL> delete from dead_lock_foreign where fid=1;
 
已刪除 1 行。

 

 

 

2:在會話2(會話ID766)裏面執行下面SQL語句:

 

 

SQL> show user;
USER is "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       766          0          1
 
SQL> delete from dead_lock_foreign where fid=2;
 
1 row deleted.

 

 

 

3:接着在會話1(會話ID789)裏執行刪除dead_lock_parentid1的記錄:

 

 

SQL> delete from dead_lock_parent where id=1;

 

 

此時你會發現會話被阻塞了,咱們能夠用下面SQL查詢具體的阻塞信息。

 

COL MODE_HELD FOR A14;
COL LOCK_TYPE FOR A8;
COL MODE_REQUESTED FOR A10;
COL OBJECT_TYPE FOR A14;
COL OBJECT_NAME FOR A20;
SELECT LK.SID,
       DECODE(LK.TYPE,
              'TX',
              'Transaction',
              'TM',
              'DML',
              'UL',
              'PL/SQL User Lock',
              LK.TYPE) LOCK_TYPE,
       DECODE(LK.LMODE,
              0,
              'None',
              1,
              'Null',
              2,
              'Row-S (SS)',
              3,
              'Row-X (SX)',
              4,
              'Share',
              5,
              'S/Row-X (SSX)',
              6,
              'Exclusive',
              TO_CHAR(LK.LMODE)) MODE_HELD,
       DECODE(LK.REQUEST,
              0,
              'None',
              1,
              'Null',
              2,
              'Row-S (SS)',
              3,
              'Row-X (SX)',
              4,
              'Share',
              5,
              'S/Row-X (SSX)',
              6,
              'Exclusive',
              TO_CHAR(LK.REQUEST)) MODE_REQUESTED, 
       OB.OBJECT_TYPE,
       OB.OBJECT_NAME,
       LK.BLOCK,
       SE.LOCKWAIT
  FROM V$LOCK LK, DBA_OBJECTS OB, V$SESSION SE
 WHERE LK.TYPE IN ('TM', 'UL')
   AND LK.SID = SE.SID
   AND LK.ID1 = OB.OBJECT_ID(+)
 AND SE.SID IN (766,789)
 ORDER BY SID;

 

 

clip_image016

 

 

 

接着在會話2(會話ID766)裏面執行下面SQL,刪除主表中id=2的記錄

 

 

SQL> delete from dead_lock_parent where id=2;

 

 

你會發現會話1(會話ID789)就會出現Deadlock

 

 

 

clip_image017

 

trace文件裏面,你能看到以下一些信息:

 

 

clip_image018

 

特徵:

 

1:在Deadlock Graph裏面有多行記錄。

2:在Deadlock Graph至少一行的鎖類型爲TM,而且Waiter等待類型爲SSX"(Share Row-eXclusive: Mode 5)

 

 

此時須要去查找對應的主外鍵約束的表,咱們能夠在PROCESS STATE裏面找到對應objectobject_id, 注意此時這個object_id不是十進制數,而是十六進制數。以下所示:

 

 

 

SQL> col object_name for a32;
SQL> select object_id, object_name from dba_objects where object_name =upper('dead_lock_foreign');
 
 OBJECT_ID OBJECT_NAME
---------- --------------------------------
    608975 DEAD_LOCK_FOREIGN
 
SQL> select to_char(608975,'xxxxx') from dual;
 
TO_CHA
------
 94acf

 

 

 

clip_image019

 

 

 

找到對應的外鍵表,而後添加索引,而後你再重複上面操做,你就會發現死鎖不會出現了。

 

 

SQL> create index idx_dead_lock_foreign_n1 on dead_lock_foreign(fid);

 

Index created.

 

 

 

關於外鍵缺乏索引,能夠詳細參考我這篇博客"ORACLE中關於外鍵缺乏索引的探討和總結"

 

 

 

3:主鍵或惟一索引更新引發的死鎖

 

 

SQL>  create table dead_lock_primary(id number(10) primary key, name varchar2(32));

 

Table created.

 

 

首先在會話(會話ID930)下執行下面SQL

 

SQL> show user;
USER is "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       930          0          1
 
SQL> insert into dead_lock_primary values(2, 'jimmy');
 
1 row created.

 

 

而後在會話2(會話ID926)裏下面執行下面SQL

 

 

SQL> show user;
USER 爲 "TEST"
SQL> select * from v$mystat where rownum =1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       926          0          1
 
SQL> insert into dead_lock_primary values(1, 'kerry');
 
已建立 1 行。

 

 

 

而後在會話1(會話ID930)下插入id=1的記錄。

 

 

SQL> insert into dead_lock_primary values(1, 'kkk');

 

 

此時在會話3下執行下面SQL,你會看到會話2被阻塞了, 以下所示:

 

 

 

SQL> @get_locked_objects_rpt.sql
Enter value for 1: 5
old  42:    AND locks_t.blocked_secs > &1
new  42:    AND locks_t.blocked_secs > 5
========= $Revision: 1.4 $ ($Date: 2013/09/16 13:15:22 $) ===========
Locked object : MONI_DDL_LOG
Locked row#   : AACg2tAAsAAAdaaAAA
Blocked for   : 238 seconds
Blocker info. : TEST@xxxx\GET253194(SID=926) [sqlplus.exe/PID=14144:10392]
Blocked info. : TEST@DB-Server.localdomain(SID=930)
[sqlplus@DB-Server.localdomain (TNS V1-V3)/PID=6806]
Blocked SQL   : insert into dead_lock_primary values(1, 'kkk')
Found 1 blocked session(s).
Disconnected from Oracle Database 10g Release 10.2.0.5.0 - 64bit Production

 

接着在會話2(會話ID926)下執行下面SQL,死鎖立馬出現:

 

 

SQL> insert into dead_lock_primary values(2, 'jimmy');

 

 

 

clip_image020

 

 

 

clip_image021

 

特徵:

 

·         More than one row in the deadlock graph

·         At Least 1 Row in the Deadlock graph is "TX X S" 

·         i.e. The Lock type is TX and the holder holds this in "X" (eXclusive: Mode 6) and waits for nothing. The waiter waits for "S" (Share:Mode 4) and waits for nothing

·         At least one of the Involved Objects is a Primary or Unique Key Index

·         Data is being Inserted or changed in an inconsistent order

 

 

4:位圖索引更新引發的死鎖。

 

 

下面咱們來看看位圖索引的更新爲何會致使死鎖。咱們先構造下面測試所需的例子:

 

 

SQLcreate table dead_lock_bitmap_index
  2  (
  3     id number(10),
  4     name varchar(30),
  5     sex number(1)
  6  );
 
Table created.
 
SQL> insert into dead_lock_bitmap_index 
  2  values(1000, 'kerry', 1);
 
1 row created.
 
SQL> insert into dead_lock_bitmap_index
  2  values(1001, 'Merry', 0);
 
1 row created.
 
SQL> insert into dead_lock_bitmap_index
  2  values(1002, 'Richard', 1);
 
1 row created.
 
SQL> insert into dead_lock_bitmap_index
  2  values(1003, 'Ken', 0);
 
1 row created.
 
SQL> commit;
 
Commit complete.
 
SQL> 
SQLcreate bitmap index idx_dead_lock_bitmap_index on dead_lock_bitmap_index(sex);
 
Index created.
 
SQL> 

 

在會話1(會話ID14)中執行下面SQL,此時sex=1的全部行都會被鎖定。

 

 

SQL> show user;
USER is "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
        14          0          0
 
SQL> update dead_lock_bitmap_index set sex=3 where id=1000 and sex=1;
 
1 row updated.

 

 

 

在會話2(會話ID69)中執行下面SQL,此時sex=0的全部行都會被鎖定

 

 

SQL> show user;
USER 爲 "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
        69          0          0
 
SQL> update dead_lock_bitmap_index set sex=4 where id=1001 and sex=0;
 
已更新 1 行。

 

 

 

在會話1(會話ID14)中執行下面SQL,此時,這個SQL語句將會被阻塞

 

 

SQL> update dead_lock_bitmap_index set sex=4 where  id=1003 and sex=0;

 

 

 

新建會話,執行下面SQL語句查看具體阻塞狀況,以下所示:

 

 

 

SQL> COL USERNAME FOR A14;
SQL> COL MACHINE  FOR A26;
SQL> COL OBJECT_NAME FOR A26;
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 
 27           AND S.SID IN ( 14,69) 
 28    ORDER  BY S.SID; 
 
       SID USERNAME       MACHINE                    TY OBJECT_NAME                LMODE           REQUEST              BLOCK
---------- -------------- -------------------------- -- -------------------------- --------------- --------------- ----------
        14 TEST           myvlnx14uat.localt.com     TM DEAD_LOCK_BITMAP_INDEX     Row Exlusive    None                     0
        14 TEST           myvlnx14uat.localt.com     TX                            None            Share                    0
        14 TEST           myvlnx14uat.localt.com     TX MRAC_OLAP2_AW_DIMENSIONS_V Exclusive       None                     0
        14 TEST           myvlnx14uat.localt.com     AE ORA$BASE                   Share           None                     0
        69 TEST           xxxx\GET253194             TM DEAD_LOCK_BITMAP_INDEX     Row Exlusive    None                     0
        69 TEST           xxxx\GET253194             TX                            Exclusive       None                     1
        69 TEST           xxxx\GET253194             AE ORA$BASE                   Share           None                     0
 
7 rows selected.
 
SQL> 

 

 

 

在會話2(會話ID69)中執行下面SQL,此時,在會話1(會話ID14)中,你就會立馬看見死鎖出現:

 

SQL> update dead_lock_bitmap_index set sex=3 where id=1002 and sex=1;

 

 

死鎖狀況以下所示:

 

 

SQL> show user;
USER is "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
        14          0          0
 
SQL> update dead_lock_bitmap_index set sex=3 where id=1000 and sex=1;
 
1 row updated.
 
SQL> 
SQL> update dead_lock_bitmap_index set sex=4 where  id=1003 and sex=0;
update dead_lock_bitmap_index set sex=4 where  id=1003 and sex=0
       *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
 
 
SQL> 

 

 

有位圖索引存在的表上面,很是容易就引起阻塞與死鎖。這個阻塞不是發生在表上面,而是發生在索引上。由於位圖索引鎖定的範圍遠遠比普通的b-tree索引鎖定的範圍大。

 

 

特徵:

 

    位圖索引更新引發的死鎖的特徵跟主鍵或惟一索引更新引發的死鎖的特徵有部分是相似的。

 

 

The typical deadlock graph for an issue caused by Bitmap Indexes locking multiple contending rows is characterised by the following:

More than one row in the deadlock graph

 

    At Least 1 Row in the Deadlock graph is "TX X S" i.e. The Lock type is TX and the holder holds this in "X" (eXclusive: Mode 6) and waits for nothing. The waiter waits for "S" (Share:Mode 4) and waits for nothing

    At Least one of the Involved Objects is a Bitmap Indexes

 

 

COLUMN OBJECT_NAME FORMAT A15
COLUMN OWNER FORMAT A10
SELECT O.OBJECT_ID,
  O.OWNER,
  O.OBJECT_NAME,
  I.INDEX_TYPE
FROM DBA_OBJECTS O,
  DBA_INDEXES I
WHERE I.OWNER(+)   =O.OWNER
AND I.INDEX_NAME(+)=O.OBJECT_NAME
AND O.OBJECT_TYPE  = 'INDEX'
AND O.OBJECT_ID    =  &OBJECT_ID 
/

 

 

clip_image022

 

 

另外關於位圖索引的選擇是有一些場景。謹慎選擇:

 

 

 

B 樹索引更適合索引動態表的 OLTP 環境,而位圖索引更適合在大型靜態表上使用複雜查詢的數據倉庫環境

 

位圖索引被存儲爲壓縮的索引值,其中包含了一個範圍內的ROWID,所以ORACLE必須針對一個給定值鎖定全部範圍內的ROWID,不支持行級別的鎖定。

 

位圖索引被存儲爲壓縮的索引值,其中包含了一個範圍內的ROWID,所以ORACLE必須針對一個給定值鎖定全部範圍內的ROWID,不支持行級別的鎖定。 

  

    換一種描述方法:使用位圖索引時,一個鍵指向多行(成百上千),若是更新一個位圖索引鍵,會同時將其餘行對應位圖索引字段進行鎖定! 

 

  較之B-Tree索引優勢: 

  位圖以一種壓縮格式存放,所以佔用的磁盤空間比B-Tree索引要小得多 

 

  較之B-Tree索引缺點: 

  這種鎖定的代價很高,會致使一些DML語句出現鎖等待,嚴重影響插入、更新和刪除的效率,對於高併發的系統不適用。 

 

  位圖索引使用原則: 

  位圖索引主要用於決策支持系統或靜態數據,不支持索引行級鎖定。

 

 

5:自治事務引起的死鎖

 

  ORACLE自制事務是指的存儲過程和函數能夠本身處理內部事務不受外部事務的影響,用PRAGMA AUTONOMOUS_TRANSACTION來聲明,要建立一個自治事務,您必須在匿名塊的最高層或者存儲過程、函數、數據包或觸發的定義部分中,使用PL/SQL中的PRAGMA AUTONOMOUS_TRANSACTION語句。在這樣的模塊或過程當中執行的SQL語句都是自治的。

 

咱們先準備測試環境,以下所示。

 

 

Connected to:
Oracle Database 10g Release 10.2.0.5.0 - 64bit Production
 
SQL> create table pat_deadlock_test(id number, name varchar(32));
 
Table created.
 
SQL> insert into pat_deadlock_test   
  2  select 1001, 'kerry' from dual union all
  3  select 1002, 'ken'   from dual;
 
2 rows created.
 
SQL> commit;
 
Commit complete.
 
SQL> --建立存儲過程,也能夠用觸發器、匿名塊等。
SQL> create or replace procedure prc_test_dead_lock as 
  2  pragma autonomous_transaction;
  3  begin
  4       update pat_deadlock_test set name='richard' where id=1002;
  5       commit;
  6  end;
  7  /
 
Procedure created.
 
SQL> 
 

 

接下來演示一下自治事務發生死鎖的狀況。以下所示

 

SQL> show user;
USER is "TEST"
SQL> select * from v$mystat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
       837          0          1
 
SQL> update pat_deadlock_test set name='kkk' where id=1002;
 
1 row updated.
 
SQL> exec prc_test_dead_lock;
BEGIN prc_test_dead_lock; END;
 
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at "TEST.PRC_TEST_DEAD_LOCK", line 4
ORA-06512: at line 1

 

 

檢查告警日誌,就能發現告警日誌裏面提示死鎖生成了trace文件 ORA-00060: Deadlock detected. More info in file /u01/app/oracle/admin/SCM2/udump/scm2_ora_30818.trc.

 

 

clip_image023

 

clip_image024

 

 

自治事務引發死鎖的特徵:

 

  This type of deadlock occurs when a single session manages to deadlock itself and is characterised by the following:

·         Only one row in the deadlock graph

·         The Row in the Deadlock graph is "TX X X" i.e. The Lock type is TX and the holder holds this in "X" (eXclusive: Mode 6) and waits for nothing. The waiter waits in "X" (eXclusive: Mode 6) and holds nothing.

·         The session is NOT involved in an autonomous transaction

 

      You can determine whether the session is involved in an autonomous transaction by searching for an "Autonomous Transaction Frames" section in the trace file:

 

 

 

6ITL死鎖

 

 

ITL概念

 

ITLInterested Transaction List)是Oracle數據塊內部的一個組成部分,用來記錄該塊全部發生的事務,有的時候也叫ITL槽位。若是一個事務一直沒有提交,那麼,這個事務將一直佔用一個ITL槽位,ITL裏面記錄了事務信息、回滾段的入口和事務類型等等。若是這個事務已經提交,那麼,ITL槽位中還保存有這個事務提交時候的SCN號。ITL的個數受表的存儲參數INITRANS控制,在一個塊內部,默認分配了2ITL的個數,若是這個塊內還有空閒空間,那麼Oracle是能夠利用這些空閒空間再分配ITL。若是沒有了空閒空間,那麼,這個塊由於不能分配新的ITL,因此,就可能發生ITL等待。若是在併發量特別大的系統中,那麼最好分配足夠的ITL個數,或者設置足夠的PCTFREE,保證ITL能擴展,可是PCTFREE有多是被行數據給消耗掉的,例如UPDATE,因此,也有可能致使塊內部的空間不夠而致使ITL等待,出現了ITL等待就可能致使ITL死鎖。

 

原本想在此總結一下ITL死鎖,不過我的看了李華榮寫的Oracle死鎖(DeadLock)的分類及其模擬ITL死鎖,感受他已經把別人想寫的都寫完了,因此,若是對TIL死鎖部分感興趣,就參考他的博客吧。

 

 

The typical ITL deadlock graph is characterised by the following:

  • More than one row in the deadlock graph
  • At Least 1 Row in the Deadlock graph is "TX X S"?
    i.e. The Lock type is TX and the holder holds this in "X" (eXclusive: Mode 6) and waits for nothing. The waiter waits for "S" (Share:Mode 4) and waits for nothing
  • None of the Involved Objects are Bitmap Indexes

Process state is likely to contain waiting for 'enq: TX - allocate ITL entry' as the current wait or as a previous wait in the recent wait stack:

clip_image026clip_image026[1]clip_image028

 

 

 

避免發生死鎖

 

 數據庫的死鎖產生是有必定條件的。死鎖產生的四個必要條件:

 

1Mutual exclusion(互斥):資源不能被共享,只能由一個進程使用。

2Hold and wait(請求並保持):已經獲得資源的進程能夠再次申請新的資源。

3No pre-emption(不可剝奪):已經分配的資源不能從相應的進程中被強制地剝奪。

4Circular wait(循環等待條件):系統中若干進程組成環路,該環路中每一個進程都在等待相鄰進程正佔用的資源。

 

 

其實死鎖的產生都是應用程序設計問題致使,咱們通常經過分析trace文件分析死鎖產生的緣由後,就能夠去破壞死鎖產生的條件,來防止死鎖產生,從而解決死鎖問題。例如,上面案例中,調整更新表的順序,外鍵增長索引等等。

 

 

 

 

 

參考資料:

 

 

http://www.cnblogs.com/lhrbest/p/6005702.html

http://www.cnblogs.com/lhrbest/articles/5388514.html

https://support.oracle.com/epmos/faces/DocumentDisplay?_afrLoop=253326631915825&id=62365.1&displayIndex=2&_afrWindowMode=0&_adf.ctrl-state=aoa3r7ym5_105

相關文章
相關標籤/搜索