zoukankan      html  css  js  c++  java
  • DB2 锁问题分析与解释

    DB2 锁问题分析与解释


    DB2 应用中常常会遇到锁超时与死锁现象。那么这样的现象产生的原因是什么呢。本文以试验的形式模拟锁等待、锁超时、死锁现象。并给出这些现象的根本原因。


    试验环境:


    DB2 v9.7.0.6
    AIX 6.1.0.0
    採用默认的隔离级别CS

    STUDENT表的DDL与初始内容
    ------------------------------------------------
    -- DDL Statements for table "E97Q6C  "."STUDENT"
    ------------------------------------------------
     
    CREATE TABLE "E97Q6C  "."STUDENT"  (
                      "AGE" INTEGER , 
                      "NAME" CHAR(8) )   
                     IN "USERSPACE1" ; 


    $ db2 "select * from student"


    AGE         NAME    
    ----------- --------
              3 xu      
              5 gao     
              2 liu     
              1 gu      







    试验1:验证insert操作与其它操作的锁等待问题


    session 1中发出insert操作。在session 2中观察insert,update,delete操作是否会锁超时。


    session 1
    ---------
    $ db2 +c "insert into student values(4, 'miao')"
    DB20000I  The SQL command completed successfully.


    session 2
    ---------
    $ db2 "insert into student values(6, 'mu')"
    DB20000I  The SQL command completed successfully.
    $ db2 "update student set name='gu' where age=1"
    DB20000I  The SQL command completed successfully.
    $ db2 "delete from student where age=2"
    DB20000I  The SQL command completed successfully.

    ----------------------------------------------------------------------------

    结论1:当session 1对表作insert操作时,session 2对该表的insert及其它行的update,delete操作都不会有问题


    ----------------------------------------------------------------------------


    试验2:验证update操作与其它操作的锁等待问题
    session 1中发出update操作,在session 2中观察insert,update,delete操作是否会锁超时。


    --------------
    session 1
    ---------
    $ db2 commit


    $ db2 "select * from student"


    AGE         NAME    
    ----------- --------
              3 xu      
              5 gao     
              6 mu      
              4 miao    
              1 gu      


      5 record(s) selected.


    $ db2 +c "update student set name = 'qing' where age=4"
    DB20000I  The SQL command completed successfully.


    session 2
    ---------
    $ db2 "insert into student values(6, 'mu')"
    DB20000I  The SQL command completed successfully.
    $ db2 "update student set name='gu' where age=1"
    DB21034E  The command was processed as an SQL statement because it was not a 
    valid Command Line Processor command.  During SQL processing it returned:
    SQL0911N  The current transaction has been rolled back because of a deadlock 
    or timeout.  Reason code "68".  SQLSTATE=40001
    $ db2 "delete from student where age=2"
    DB21034E  The command was processed as an SQL statement because it was not a 
    valid Command Line Processor command.  During SQL processing it returned:
    SQL0911N  The current transaction has been rolled back because of a deadlock 
    or timeout.  Reason code "68".  SQLSTATE=40001


    ----------------------------------------------------------------------------
    结论2:当session 1对表某一行做update操作时。session 2能够对该表作insert操作,但不同意对其它行的delete和update操作
    ----------------------------------------------------------------------------


    试验3:验证delete操作与其它操作的锁等待问题
    session 1中发出delete操作,在session 2中观察insert,update,delete操作是否会锁超时。


    Session 1
    ---------
    $ db2 commit


    $ db2 +c "delete from student where age=4"
    DB20000I  The SQL command completed successfully.


    session 2
    ---------
    $ db2 "insert into student values(6, 'mu')"
    DB20000I  The SQL command completed successfully.


    $ db2 "update student set name='gu' where age=1"
    DB21034E  The command was processed as an SQL statement because it was not a 
    valid Command Line Processor command.  During SQL processing it returned:
    SQL0911N  The current transaction has been rolled back because of a deadlock 
    or timeout.  Reason code "68".  SQLSTATE=40001


    $ db2 "delete from student where age=2"
    DB21034E  The command was processed as an SQL statement because it was not a 
    valid Command Line Processor command.  During SQL processing it returned:
    SQL0911N  The current transaction has been rolled back because of a deadlock 
    or timeout.  Reason code "68".  SQLSTATE=40001
    ----------------------------------------------------------------------------
    结论3:当应用1对表某一行做delete操作时,应用2能够对该表作insert操作,但不同意对其它行的delete和update操作
    ----------------------------------------------------------------------------


    总的结论是:
    应用对表作insert操作时,其它操作不受影响,也不受其它操作影响。
    作update,delete操作时,其它的update和delete操作受影响。


    为了解释以上现象的原因。我们首先看一下上面的操作须要什么样的锁。


    session 1.
    ---------
    $ db2 rollback


    $ db2 +c "insert into student values(7,'han')"
    DB20000I  The SQL command completed successfully.


    $ db2pd -db qsmiao -locks


    结论:insert操作须要表级的IX锁和行级的X锁。


    注:IX锁,该锁的拥有者在拥有对应行的X锁时能够更改该行的数据。


    $ db2 rollback


    $ db2 +c "update student set name='yan' where age=5"
    DB20000I  The SQL command completed successfully.


    $ db2pd -db qsmiao -locks




    结论:update操作须要表级的IX锁和行级的X锁。


    $ db2 rollback


    $ db2 +c "delete from student where age=6"

    DB20000I  The SQL command completed successfully.


    $ db2pd -db qsmiao -locks




    结论:update操作须要表级的IX锁和相应的行级的X锁(这里由于3条记录的age都为6,因此须要3个行级锁)。


    如今的问题是:为什么insert和update,delete操作须要的锁一样(表级的IX锁,相应行级的X锁),可是表现的效果却不一样呢?


    为了解决问题,看一下他们的运行计划吧:


    $ db2expln -d qsmiao -g -statement "insert into student values(5, 'gao')" -terminal



    $ db2expln -d qsmiao -g -statement "update student set name='qing' where age=4" -terminal





    $ db2expln -d qsmiao -g -statement "delete from student where age=6" -terminal




    从上面的运行计划中能够看到原因:insert操作不须要表扫描,而update和delete操作都须要全表扫描。并且会在扫描的时候试图对每一行加U锁。
    导致锁超时的原因就是表扫描
    比如session 1要更新表的某一行。会在该行加上X锁。之后, session 2试图更新该表的还有一行,进行全表扫描时,就会试图对A占用的那一行加上U锁,但无能为力,终于导

    致锁超时。


    为了验证该说法。能够抓取锁等待的消息,


    session 1
    ---------
    $ db2 +c "update student set name='hehe' where age = 4"
    DB20000I  The SQL command completed successfully.


    session 2
    ---------
    $ db2 +c "delete from student where age=6"
           <-------这时会hang住,由于它在等session 1的锁


    session 3
    ---------
    $ db2pd -db qsmiao -wlocks  <---在锁超时发生之前,抓取锁等待的消息

    Locks being waited on :
    AppHandl [nod-index] TranHdl    Lockname                                   Type       Mode Conv Sts      CoorEDU  AppName  AuthID   AppID                           
    15393    [000-15393] 2               00020004000000000000000952 Row        ..X       G    7818       db2bp    E97Q6C   *LOCAL.e97q6c.141016035113       
    15408    [000-15408] 16             00020004000000000000000952 Row        ..U       W   10153      db2bp    E97Q6C   *LOCAL.e97q6c.141016035219     


    能够看到。是由于U锁和X锁的不兼容导致锁等待,最后导致锁超时。



    为了解决该锁等待问题,能够在查询谓词所涉及的列age上建立索引,避免全表扫描


    试验4:通过建立索引,消除锁等待现象


    session 1
    ---------
    $ db2 rollback


    $ db2 +c "lock table student in share mode"


    $ db2 +c "create index stu_idx on student(age)"


    $ db2 commit


    $ db2 +c "update student set name='hehe' where age = 4"
    DB20000I  The SQL command completed successfully.


    session 2
    ---------
    $ db2 +c "delete from student where age=6"  <--没有发生锁等待现象,直接成功
    DB20000I  The SQL command completed successfully.


    能够看到。已经通过索引攻克了该锁超时问题。假设读者有兴趣的话,能够看下建立索引之后的訪问计划。






    以下模拟一个死锁现象
    试验5:模拟死锁,步骤例如以下
    第一步:session 1 获得 锁 LOCK1


    第二步:session 2 获得 锁 LOCK2


    第三步:session 2 申请 锁 LOCK1


    第四步:session 1 申请 锁 LOCK2


    为了避免死锁之前产生锁超时,先将锁超时控制參数设为-1(表示永远等待)
    update db cfg using locktimeout -1
    之后重新启动数据库


    session 1
    ---------
    $ db2 +c "update student set name = 'an' where age = 1"       <--获得锁LOCK1,成功
    DB20000I  The SQL command completed successfully.


    session 2
    ---------
    $ db2 +c "update student set name = 'two' where age = 4"      <--获得锁LOCK2,成功
    DB20000I  The SQL command completed successfully.


    $ db2 +c "update student set name = 'four' where age = 1"     <--申请锁LOCK1。hang住,由于LOCK1被session 1持有


    session 1
    ---------
    $ db2 +c "update student set name = 'three' where age = 4"    <--申请锁LOCK2,hang住,由于LOCK2被session 2持有




    这时已经发生了死锁,10s之后,这两个session有一个会报出例如以下死锁(reason code 2)错误。还有一个session成功运行
    SQL0911N  The current transaction has been rolled back because of a deadlock 
    or timeout.  Reason code "2".  SQLSTATE=40001


    參考资料:
    标准表的锁定方式和存取方案,这里您能够看到具体的加锁方式
    http://www-01.ibm.com/support/knowledgecenter/SSEPGG_9.7.0/com.ibm.db2.luw.admin.perf.doc/doc/r0005275.html?

    lang=zh


    附。仅仅能在发生死锁或者锁等待的时候才干用db2pd查看锁的信息。以下附上怎样採用事件监控器监控死锁/锁超时。事件监控器能够抓取一段时间内的锁事件
    db2 update db cfg for sample using MON_LOCKWAIT hist_and_values MON_DEADLOCK hist_and_values MON_LOCKTIMEOUT hist_and_values MON_LW_THRESH 10000
    db2 "CREATE EVENT MONITOR LOCKEVMON FOR LOCKING WRITE TO UNFORMATTED EVENT TABLE (TABLE LOCKEVMON)"
    db2 set event monitor LOCKEVMON state=1


    重现问题


    db2 flush event monitor LOCKEVMON
    db2 set event monitor LOCKEVMON state=0


    cp /home/db2users/e97q6c/sqllib/samples/java/jdbc/db2evmonfmt.java ./
    cp /home/db2users/e97q6c/sqllib/samples/java/jdbc/DB2EvmonLocking.xsl ./
    export PATH=/home/db2users/e97q6c/sqllib/java/jdk64/bin:$PATH


    javac db2evmonfmt.java


    java db2evmonfmt -d sample -ue LOCKEVMON -ftext -u e97q6c -p e97q6c > deadlock.txt
    more deadlock.txt 能够看到有关的SQL语句。




    请參考

    http://www.ibm.com/developerworks/cn/data/library/techarticles/dm-1004lockeventmonitor/

    http://blog.csdn.net/qingsong3333/article/details/51206329


  • 相关阅读:
    [转]SVN服务器搭建和使用(二)
    [转]SVN服务器搭建和使用(一)
    BZOJ 2049 Sdoi2008 Cave 洞穴勘测
    BZOJ 1589 Usaco2008 Dec Trick or Treat on the Farm 采集糖果
    BZOJ 2796 POI2012 Fibonacci Representation
    BZOJ 2115 Wc2011 Xor
    BZOJ 3105 CQOI2013 新Nim游戏
    BZOJ 2460 Beijing2011 元素
    BZOJ 3687 简单题
    BZOJ 1068 SCOI2008 压缩
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/6764176.html
Copyright © 2011-2022 走看看