• oracle 锁的概念


    一 锁(Lock)

      01,锁的概念

    数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数
    据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可
    能会读取和存储不正确的数据,破坏数据库的一致性。  
     
    加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对
    象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了
    一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作。  
     
    在Oracle 数据库中,它并不是对某个表加上锁或者某几行加上锁,锁是以
    数据块的一个属性存在的。 也就是说,每个数据块本身就存储着自己数据块中
    数据的信息,这个地方叫ITL(Interested Transaction List),凡是在这个数据块上有活动的事务,它的信息就会记录在这里面供后续的操作查询,一保证事务的一
    致性。 

    二 ,锁的分类

      按用户与系统划分,可以分为自动锁与显示锁      

        a) 自动锁(Automatic Locks):

          当进行一项数据库操作时,缺省情况下,系统自动为此数据库操作获得所有有必要的锁。自动锁分DML锁,DDL锁,system  locks。    

        b) 显示锁(Manual Data Locks):

                某些情况下,需要用户显示的锁定数据库操作要用到的数据,才能使数据库操作执行得更好,显示锁是用户为数据库对象设定的。

      按锁级别划分,可分为: 排它锁(Exclusive  Locks,即X锁)和共享锁(Share Locks,即S锁)

        a) 共享锁(  S  ):

          共享锁使一个事务对特定数据库资源进行共享访问——另一事务也可对此资源进行访问或获得相同共享锁。共享锁为事务提供高并发性,但如拙劣的事务设计+共享锁容易造成死锁或数据更新丢失。

                  b) 排它锁(  X):

          事务设置排它锁后,该事务单独获得此资源,另一事务不能在此事务提交之前获得相同对象的共享锁或排它锁。 

       按操作划分,可分为DML锁(data  locks,数据锁)、DDL锁(data dictionary lock)和 System Locks。 

        a) DML锁

    DML 锁用于控制并发事务中的数据操纵,保证数据的一致性和完整性。
    DML锁主要用于保护并发情况下的数据完整性。
    DML 语句能够自动地获得所需的表级锁(TM)与行级(事务)锁(TX)。
    它又分为: 
    ( 1) TM 锁(表级锁) 
    ( 2) TX 锁( 事务锁或行级锁)
    
    当 Oracle 执行 DML 语句时,系统自动在所要操作的表上申请 TM 类型的锁。当 TM 锁获得后,系统再自动申请 TX 类型的锁,
    并将实际锁定的数据行的锁标志位进行置位。 这样在事务加锁前检查 TX锁相容性时就不用再逐行检查锁标志,而只需检查 TM 锁模式的相容性即可,大大提高了系统的效率。 在数据行上只有 X 锁(排他锁)。 在 Oracle 数据库中,当一个事务首次发起一个 DML 语句时就获得一个 TX 锁,该锁保持到事务被提交或回滚。
    当两个或多个会话在表的同一条记录上执行 DML 语句时,第一个会话在该条记录上加锁,其他的会话处于等待状态。当第一个会话提交后, TX 锁被释放,
    其他会话才可以加锁。 当 Oracle 数据库发生 TX 锁等待时,如果不及时处理常常会引起 Oracle 数据库挂起,或导致死锁的发生,产生ORA
    -600 的错误。
    这些现象都会对实际应用产生极大的危害,如长时间未响应,大量事务失败等。

        A,1)TM锁(表锁)

    TM 锁用于确保在修改表的内容时,表的结构不会改变,例如防止在 DML 语句执行期间相关的表被移除。当用户对表执行 DDL 或 DML 操作时,
    将获取一个此表的表级锁。 当事务获得行锁后,此事务也将自动获得该行的表锁(共享锁),以防止其它事务进行 DDL 语句影响记录行的更新。 事务也可以在进行过程中获得共享锁或排它锁,只有当事务显示使用 LOCK TABLE 语 句显示的定义一个排它锁时,事务才会获得表上的排它锁,
    也可使用 LOCK TABLE 显示的定义一个表级的共享锁。 TM 锁包括了 SS、 SX、 S、 X 等多种模式,在数据库中用
    06 来表示。不同的 SQL 操作产生不同类型的 TM 锁

        A,2) TX 锁( 事务锁或行级锁)

    当事务执行数据库插入、更新、删除操作时,该事务自动获得操作表中操作行的排它锁。
    
    事务发起第一个修改时会得到TX 锁(事务锁),而且会一直持有这个锁,直至事务执行提交(COMMIT)或回滚(ROLLBACK)。
    
    对用户的数据操纵, Oracle 可以自动为操纵的数据进行加锁,但如果有操纵授权,则为满足并发操纵的需要另外实施加锁。
    
    DML 锁可由一个用户进程以显式的方式加锁,也可通过某些 SQL 语句隐含方式实现。 这部分属于 Manual Data Locks。
    
    原理:一个事务要修改块中的数据,必须获得该块中的一个itl,通过itl和undo segment header中的transaction table,
    可以知道事务是否处于活动阶段。事务在修改块时(其实就是在修改行)会检查行中row header中的标志位,如果该标志位为0(该行没有被活动的事务锁住),
    就把该标志位修改为事务在该块获得的itl的序号,这样当前事务就获得了对记录的锁定,然后就可以修改行数据了,这也就是oracle行锁实现的原理。 DML 锁有如下三种加锁方式: 共享锁方式( SHARE) 独占锁方式( EXCLUSIVE) 共享更新锁( SHARE UPDATE)
    其中: SHARE, EXCLUSIVE 用于 TM 锁(表级锁) SHARE UPDATE 用于 TX 锁( 行级锁)

    (1)共享锁方式( SHARE)

    共享方式的表级锁是对表中的所有数据进行加锁,该锁用于保护查询数据的一致性,防止其它用户对已加锁的表进行更新。

    其它用户只能对该表再施加共享方式的锁,而不能再对该表施加独占方式的锁,共享更新锁可以再施加,但不允许持有共享更新封锁的进程做更新。

    共享该表的所有用户只能查询表中的数据,但不能更新。

    共享方式的表级锁只能由用户用 SQL 语句来设置.

    LOCK TABLE <表名>[,<表名>]...   IN SHARE MODE [NOWAIT]   

    执行该语句,对一个或多个表施加共享方式的表封锁。当指定了选择项  NOWAIT,若该锁暂时不能施加成功,则返回并由用户决定是进行等待,还是先去执行别的语句。  

    持有共享锁的事务,在出现如下之一的条件时,便释放其共享锁: 
    A、执行COMMIT或ROLLBACK语句。
    B、退出数据库(LOG OFF)。
    C、程序停止运行。
     
    共享方式表级锁常用于一致性查询过程,即在查询数据期间表中的数据不发生改变。

     
    (2)独占方式表级锁(Exclusive)

    独占方式表级锁是用于加锁表中的所有数据,拥有该独占方式表封锁的用户,即可以查询该表,又可以更新该表,其它的用户不能再对该表施加任何加锁
    (包括共享、独占或共享更新封锁)。其它用户虽然不能更新该表,但可以查询该表。

    独占方式的表封锁可通过如下的SQL语句来显示地获得:
    LOCK TABLE <表名>[,<表名>].... IN EXCLUSIVE MODE [NOWAIT]
    独占方式的表级锁也可以在用户执行DML语句INSERT、UPDATE、DELETE时隐含获得。
    拥有独占方式表封锁的事务,在出现如下条件之一时,便释放该封锁:
    (1)、执行COMMIT或ROLLBACK语句。
    (2)、退出数据库(LOG OFF)
    (3)、程序停止运行。

    独占方式封锁通常用于更新数据,当某个更新事务涉及多个表时,可减少发生死锁。

     
    (3)共享更新加锁方式(Share Update)

    共享更新加锁是对一个表的一行或多行进行加锁,因而也称作行级加锁。表级加锁虽然保证了数据的一致性,但却减弱了操作数据的并行性。行级加锁确保
    在用户取得被更新的行到该行进行更新这段时间内不被其它用户所修改。因而行级锁即可保证数据的一致性又能提高数据操作的迸发性。
    可通过如下的两种方式来获得行级封锁:
    (1)、执行如下的SQL封锁语句,以显示的方式获得:
    LOCK  TABLE  <表名>[,<表名>]....  IN  SHARE  UPDATE  MODE
    [NOWAIT]
     
    (2)、用如下的SELECT ...FOR UPDATE语句获得:
    SELECT  <列名>[,<列名>]...FROM  <表名>  WHERE  <条件>  FOR
    UPDATE OF <列名>[,<列名>].....[NOWAIT]
    一旦用户对某个行施加了行级加锁,则该用户可以查询也可以更新被加锁的数据行,其它用户只能查询但不能更新被加锁的数据行.如果其它用户想更新该
    表中的数据行,则也必须对该表施加行级锁.即使多个用户对一个表均使用了共享更新,但也不允许两个事务同时对一个表进行更新,真正对表进行更新时,是
    以独占方式锁表,一直到提交或复原该事务为止。行锁永远是独占方式锁。
     
    当出现如下之一的条件,便释放共享更新锁:
    (1)、执行提交(COMMIT)语句;
    (2)、退出数据库(LOG OFF)
    (3)、程序停止运行。
     
    执行ROLLBACK操作不能释放行锁。

        b) DDL锁(dictionary locks)

           DDL锁用于保护数据库对象的结构,如表、索引等的结构定义。 DDL锁又可以分为:排它DDL锁、共享DDL锁、分析锁
              1) 排它DDL锁:

    创建、修改、删除一个数据库对象的DDL语句获得操作对象的 排它锁。如使用alter  table语句时,为了维护数据的完成性、一致性、合法性,该事务获得一排
    它DDL锁。

          (2) 共享DDL锁:

    需在数据库对象之间建立相互依赖关系的DDL语句通常需共享获得DDL锁。如创建一个包,该包中的过程与函数引用了不同的数据库表,当编译此包时,
    该事务就获得了引用表的共享DDL锁。 

          (3) 分析锁:

    ORACLE使用共享池存储分析与优化过的SQL语句及PL/SQL程序,使运行相同语句的应用速度更快。一个在共享池中缓存的对象获得它所引用数据库对
    象的分析锁。分析锁是一种独特的DDL锁类型,ORACLE使用它追踪共享池对象及它所引用数据库对象之间的依赖关系。当一个事务修改或删除了共享池持有
    分析锁的数据库对象时,ORACLE使共享池中的对象作废,下次在引用这条SQL/PLSQL语 句时,ORACLE重新分析编译此语句。
     
    DDL级加锁也是由ORACLE RDBMS来控制,它用于保护数据字典和数据定义改变时的一致性和完整性。它是系统在对SQL定义语句作语法分析时自动
    地加锁,无需用户干予。
     
    字典/语法分析加锁共分三类:
    (1)字典操作锁:
    用于对字典操作时,锁住数据字典,此封锁是独占的,从而保护任何一
    个时刻仅能对一个字典操作。
    (2)字典定义锁:
    用于防止在进行字典操作时又进行语法分析,这样可以避免在查询字典
    的同时改动某个表的结构。
    (3)表定义锁:
    用于一个SQL语句正当访问某个表时,防止字典中与该表有关的项目被
    修改。  

      死锁

    死锁
    当两个用户希望持有对方的资源时就会发生死锁.
    即两个用户互相等待对方释放资源时,oracle认定为产生了死锁,在这种情况下,将以牺牲一个用户作为代价,另一个用户继续执行,牺牲的用户的事务将回滚。
    场景
    1:用户 1 对 A 表进行 Update,没有提交。 
    2:用户 2 对 B 表进行 Update,没有提交。
    此时双反不存在资源共享的问题。
    3:如果用户 2 此时对 A 表作 update,则会发生阻塞,需要等到用户一的事物结束。 
    4:如果此时用户 1 又对 B 表作 update,则产生死锁。此时 Oracle 会选择其中一个用户进行会滚,使另一个用户继续执行操作。
    起因:  
    Oracle的死锁问题实际上很少见,如果发生,基本上都是不正确的程序设计造成的,经过调整后,基本上都会避免死锁的发生。 
    在Oracle系统中能自动发现死锁,并选择代价最小的,即完成工作量最少的事务予以撤消,释放该事务所拥有的全部锁,记其它的事务继续工作下去。 
     从系统性能上考虑,应该尽可能减少资源竞争,增大吞吐量,因此用户在给并发操作加锁时,应注意以下几点: 
      1、对于UPDATE和DELETE操作,应只锁要做改动的行,在完成修改后立即提交。 
      2、当多个事务正利用共享更新的方式进行更新,则不要使用共享封锁,而应采用共享更新锁,这样其它用户就能使用行级锁,以增加并行性。 
    3、尽可能将对一个表的操作的并发事务施加共享更新锁,从而可提高并行性。 4、在应用负荷较高的期间,不宜对基础数据结构(表、索引、簇和视图)进行修改 如果死锁不能自动释放,就需要我们手工的kill session。

    三,锁的操作

      01,创建锁

    生成锁,即启动三个连接到oracle数据库,两台同时操作一个表,另一台查看争用用情况

      02,查看死锁情况

    SELECT   'alter system kill session ''' || sid || ',' || serial# || ''';'  
    "Deadlock" 
      FROM   v$session 
     WHERE   sid IN (SELECT   sid 
                       FROM   v$lock 
                      WHERE   block = 1);

    需要注意的是id再100以下可能是一个aplication,对应的是事务才能kill

      03,跟踪问题 的sql

     SELECT   s.sid, q.sql_text 
        FROM   v$sqltext q, v$session s 
       WHERE   q.address = s.sql_address AND s.sid = &sid  
    ORDER BY   piece;  

     点击后要求输入id,这个为查询出来的id值

      04,查看谁锁了谁

    SELECT      s1.username 
             || '@' 
             || s1.machine 
             || ' ( SID=' 
             || s1.sid 
             || ' )  is blocking ' 
             || s2.username 
             || '@' 
             || s2.machine 
             || ' ( SID=' 
             || s2.sid 
             || ' ) ' 
                AS blocking_status 
      FROM   v$lock l1, 
             v$session s1, 
             v$lock l2, 
             v$session s2 
     WHERE       s1.sid = l1.sid 
             AND s2.sid = l2.sid 
             AND l1.BLOCK = 1 
             AND l2.request > 0 
             AND l1.id1 = l2.id1 
             AND l2.id2 = l2.id2;

    或者这样查看

    SQL> col USER_NAME format a10;
    SQL> col OWNER format a10;
    SQL> col OBJECT_NAME format a10;
    SQL> col OBJECT_TYPE format a10;
    SQL>   SELECT
            LPAD (' ', DECODE (l.xidusn, 0, 3, 0))
               || l.oracle_username
                  User_name,
               o.owner,
               o.object_name,
               o.object_type,
               s.sid,
               s.serial#
        FROM   v$locked_obje  2    3    4    5    6    7    8    9   10  ct l, dba_objects o, v$session s
       WHERE   l.object_id = o.object_id AND l.session_id = s.sid
    ORDER BY   o.object_id, xidusn DESC  11   12  ;
    
    USER_NAME  OWNER      OBJECT_NAM OBJECT_TYP       SID      SERIAL#
    ---------- ---------- ---------- ---------- ---------- ----------
    SYS       SYS          T      TABLE           276         6522
    SYS       SYS          T      TABLE            29        25094

    四,锁与阻塞

      01,概念

      通常来讲,系统如果平时运行正常,突然会停止不动,多半是被阻塞(Blocked)住了。 我们可以通过v$lock 这张视图,看查看阻塞的信息。
      锁的视图:

    SQL> desc v$lock
     Name                       Null?    Type
     ----------------------------------------- -------- ----------------------------
     ADDR                            RAW(8)
     KADDR                            RAW(8)
     SID                            NUMBER
     TYPE                            VARCHAR2(2)
     ID1                            NUMBER
     ID2                            NUMBER
     LMODE                            NUMBER
     REQUEST                        NUMBER
     CTIME                            NUMBER
     BLOCK                            NUMBER
     CON_ID                         NUMBER
    SQL> select * from v$lock;
    
    ADDR         KADDR             SID TY        ID1      ID2       LMODE    REQUEST     CTIME        BLOCK     CON_ID
    ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- ----------
    000000007DABD000 000000007DABD080     246 MR     21        0           4      0    165382        0       0
    000000007DAC0640 000000007DAC06C0       7 KT      18972    5           4      0    510918        0       0
    000000007DABCBA0 000000007DABCC20     247 XR      4        0           1      0         0        0       0
    000000007DABCA88 000000007DABCB08     247 RD      1        0           1      0    693013        0       0
    000000007DABC970 000000007DABC9F0     247 CF      0        0           2      0    693013        0       0
    000000007DABCDD0 000000007DABCE50      10 RT      1        0           6      0    693009        0       0
    000000007DABCCB8 000000007DABCD38     247 RS     25        1           2      0    693009        0       0
    000000007DABD248 000000007DABD2C8     246 MR      3        0           4      0    693009        0       0
    000000007DABDA08 000000007DABDA88     246 MR      5        0           4      0    693008        0       0
    000000007DABE3F8 000000007DABE478     246 MR      6        0           4      0    693008        0       0
    000000007DABF018 000000007DABF098     246 MR      9        0           4      0    692971        0       0
    
    ADDR         KADDR             SID TY        ID1      ID2       LMODE    REQUEST     CTIME        BLOCK     CON_ID
    ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- ----------
    000000007DABDF80 000000007DABE000     246 MR      203      0           4      0    692971        0       0
    000000007DABD590 000000007DABD610     246 MR      1        0           4      0    693009        0       0
    000000007DABCEE8 000000007DABCF68     246 MR      4        0           4      0    693009        0       0
    000000007DABD6A8 000000007DABD728     246 MR      7        0           4      0    693009        0       0
    000000007DABD7C0 000000007DABD840     246 MR      201      0           4      0    693009        0       0
    000000007DAC0DE8 000000007DAC0E68     246 MR     19        0           4      0    167393        0       0
    000000007DABD478 000000007DABD4F8     248 TS      3        1           3      0    693009        0       1
    000000007DABD8D8 000000007DABD958       7 KD      0        0           6      0    693009        0       0
    000000007DABE1B0 000000007DABE230     246 MR      8        0           4      0    693008        0       0
    000000007DABD360 000000007DABD3E0      16 AE      133      1           4      0    693008        0       0
    000000007DABDD50 000000007DABDDD0     275 AE      133      1           4      0       451        0       0
    
    ADDR         KADDR             SID TY        ID1      ID2       LMODE    REQUEST     CTIME        BLOCK     CON_ID
    ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- ----------
    000000007DABECD0 000000007DABED50     276 AE        133        1           4      0     14025        0       0
    000000007DAC1260 000000007DAC12E0      29 AE        133        1           4      0     11965        0       0
    000000007DAC0758 000000007DAC07D8       7 KT      18972        3           4      0     17990        0       0
    000000007DABF130 000000007DABF1B0     246 MR         10        0           4      0    692971        0       0
    000000007DABC858 000000007DABC8D8     246 MR        204        0           4      0    512035        0       0
    000000007DABE2E0 000000007DABE360     246 MR        202        0           4      0    693008        0       0
    000000007DABDC38 000000007DABDCB8     246 PW          1        0           3      0    693007        0       0
    000000007DAC0870 000000007DAC08F0     246 MR         18        0           4      0    510918        0       0
    000000007DABF248 000000007DABF2C8     246 MR         11        0           4      0    692971        0       0
    000000007DABE628 000000007DABE6A8       7 KT      18972        2           4      0    693008        0       0
    000000007DABFF98 000000007DAC0018     246 MR         22        0           4      0    165311        0       0
    
    ADDR         KADDR             SID TY        ID1      ID2       LMODE    REQUEST     CTIME        BLOCK     CON_ID
    ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- ----------
    000000007DAC0BB8 000000007DAC0C38       7 KT      18972        4           4      0    512035        0       0
    000000007DAC0988 000000007DAC0A08     246 MR         15        0           4      0    512035        0       0
    000000007DABF360 000000007DABF3E0     246 MR         12        0           4      0    692971        0       0
    000000007DABEDE8 000000007DABEE68     248 TS          3        1           3      0    689410        0       3
    000000007DABF8F0 000000007DABF970      29 TX      65541     1671           0      6       397        0       1
    000000007ADFBA08 000000007ADFBA90     276 TX      65541     1671           6      0       406        1       1
    000000007DAC0AA0 000000007DAC0B20       7 KT      19005        1           4      0      3591        0       0
    000000007DABF490 000000007DABF510     248 TS          3        1           3      0    513214        0       4
    000000007DAC0510 000000007DAC0590     246 MR         17        0           4      0    510918        0       0
    000000007DABEA88 000000007DABEB08     246 MR         13        0           4      0    512035        0       0
    000000007DAC03F8 000000007DAC0478     246 MR         14        0           4      0    512035        0       0
    
    ADDR         KADDR             SID TY        ID1      ID2       LMODE    REQUEST     CTIME        BLOCK     CON_ID
    ---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ---------- ----------
    000000007DABFA08 000000007DABFA88     246 MR        205        0           4      0    510918        0       0
    000000007DAC00B0 000000007DAC0130     246 MR         20        0           4      0    165939        0       0
    000000007DABFC38 000000007DABFCB8     246 MR         16        0           4      0    510918        0       0
    00007FD03B161448 00007FD03B1614B8      29 TM      75220        0           3      0       397        0       1
    00007FD03B161448 00007FD03B1614B8     276 TM      75220        0           3      0     11897        0       1
    
    49 rows selected.

     我们关注的比较多的是request 和 block 字段。
    如果某个request列是一个非0值,那么它就是在等待一个锁。  如果block列是1,这个SID 就持有了一个锁,并且阻塞别人获得这个锁。 这个锁的类型由TYPE 字段定义。锁的模式有LMODE 字段定义,ID1 和ID2 字段定义了这个锁的相关信息。ID1相同,就代表指向同一个资源。 这样就有可能有加锁者和等待者。 

    参考下面的TM锁类型表。 

    结合 v$lock 和 v$session 视图来查询相关的信息:

    SQL> SELECT sn.username,
           m.SID,
           sn.SERIAL#,
           m.TYPE,
           DECODE(m.lmode,
                  0,
                  'None',
                  1,
                  'Null',
                  2,
                  'Row Share',
                  3,
                  'Row Excl.',  2    3    4    5    6    7    8    9   10   11   12   13
                  4,
                  'Share',
                  5,
                  'S/Row Excl.',
                  6,
                  'Exclusive',
                  lmode,
                  LTRIM(TO_CHAR(lmode, '990'))) lmode,
           DECODE(m.request,
                  0,
                14   15   16   17   18   19   20   21   22   23   24     'None',
                  1,
                  'Null',
                  2,
                  'Row Share',
                  3,
                  'Row Excl.',
                  4,
                  'Share',
                  5,
                  'S/Row Excl.',
                  6,
                  ' 25   26   27   28   29   30   31   32   33   34   35   36  Exclusive',
                  request,
                  LTRIM(TO_CHAR(m.request, '990'))) request,
           m.id1,
           m.id2
      FROM v$session sn, v$lock m
     WHERE (sn.SID = m.SID AND m.request != 0)
          --存在锁请求,即被阻塞
        OR (sn.SID = m.SID
       37   38   39   40   41   42   43   44   45       --不存在锁请求,但是锁定的对象被其他会话请求锁定
           AND m.request = 0 AND lmode != 4 AND
           (id1, id2) IN (SELECT s.id1, s.id2
                             FROM v$lock s
                            WHERE request != 0
                              AND s.id1 = m.id1
                              AND s.id2 = m.id2))
     ORDER BY id1, id2, m.request; 46   47   48   49   50   51   52
    
    USERNAME                                                            SID    SERIAL# TY LMODE       REQUEST         ID1        ID2
    -------------------------------------------------------------------------------------------------------------------------------- ---------- ---------- -- ----------- ----------- ---------- ----------
    SYS                                                                276      6522 TX Exclusive   None           65541       1671
    SYS29     25094 TX None          Exclusive        65541       1671
    
    SQL>

    或者通过下面查询

    SQL> SELECT /*+ rule */
     s.username,
     DECODE(l.TYPE, 'TM', 'TABLE LOCK', 'TX', 'ROW LOCK', NULL) lock_level,
     o.owner,
     o.object_name,
     o.object_type,
     s.sid,
     s.serial#,
     s.terminal,
     s.machine,
     s.program,
     s.osuser
      FROM v$session s, v$lock l, dba_objects o  2    3    4    5    6    7    8    9   10   11   12   13
     WHERE l.sid = s.sid
       AND l.id1 = o.object_id(+)
       AND s.username IS NOT NULL; 14   15   16
    
    USERNAMELOCK_LEVEL OWNER      OBJECT_NAM OBJECT_TYP        SID    SERIAL# TERMINAL              MACHINE  PROGRAM                        OSUSER
    -------------------------------------------------------------------------------------------------------------------------------- ---------- ----
    SYS   SYS        ORA$BASE   EDITION         29      25094 pts/3              node12c01  sqlplus@node12c01 (TNS V1-V3)            oracle
    SYSROW LOCK   PUBLIC     oracle/ord SYNONYM         29      25094 pts/3              node12c01  sqlplus@node12c01 (TNS V1-V3)            oracle
          /media/jai
          /io/Memory
          CacheSeeka
          bleOutputS
          tream
    
    SYSTABLE LOCK SYS        T      TABLE          29      25094 pts/3              node12c01  sqlplus@node12c01 (TNS V1-V3)            oracle
    SYSTABLE LOCK SYS        T      TABLE         276       6522 pts/0              node12c01  sqlplus@node12c01 (TNS V1-V3)            oracle
    SYSROW LOCK   PUBLIC     oracle/ord SYNONYM        276       6522 pts/0              node12c01  sqlplus@node12c01 (TNS V1-V3)            oracle
    
    USERNAMELOCK_LEVEL OWNER      OBJECT_NAM OBJECT_TYP        SID    SERIAL# TERMINAL              MACHINE  PROGRAM                        OSUSER
    -------------------------------------------------------------------------------------------------------------------------------- ---------- ---
          CacheSeeka
          bleOutputS
          tream
    
    SYS   SYS        ORA$BASE   EDITION        276       6522 pts/0              node12c01  sqlplus@node12c01 (TNS V1-V3)            oracle
    SYS   SYS        ORA$BASE   EDITION        275      12753 pts/4              node12c01  sqlplus@node12c01 (TNS V1-V3)            oracle
    
    7 rows selected.
    
    SQL>

    引起阻塞的几种常见情况  

     (1)DML语句引起阻塞

    当一个会话保持另一个会话正在请求的资源上的锁定时,就会发生阻塞。被阻塞的会话将一直挂起,直到持有锁的会话放弃锁定的资源为止。 
    4个常见的dml语句会产生阻塞: 
        (1INSERT2UPDATE3DELETE4SELECTFOR UPDATE  
    INSERT   
    Insert 发生阻塞的唯一情况就是用户拥有一个建有主键约束的表。当2个的会话同时试图向表中插入相同的数据时,其中的一个会话将被阻塞,直到另外一个会话提交或会滚。
    一个会话提交时,另一个会话将收到主键重复的错误。回滚时,被阻塞的会话将继续执行。 
    UpdateDelete UPDATE 和DELETE当执行Update和delete操作的数据行已经被另外的会话锁定时,将会发生阻塞,直到另一个会话提交或会滚。   
    Selectfor update  
    当一个用户发出select..for update的错作准备对返回的结果集进行修改时,如果结果集已经被另一个会话锁定,此时Oracle已经对返回的结果集上加了排它
    的行级锁,所有其他对这些数据进行的修改或删除操作都必须等待这个锁的释放(操作commit或rollback.),产生的外在现象就是其他的操作将发生阻塞. 
    同样这个查询的事务将会对该表加表级锁,不允许对该表的任何ddl操作,否则将会报出Ora-00054:resource busy and acquire with nowait specified. 
     
    可以通过发出 selectfor  update  nowait的语句来避免发生阻塞,如果资源已经被另一个会话锁定,则会返回以下错误:Ora-00054:resource busy and acquire 
    with nowait specified.  
     

      (2)外键没有创建索引

      如果系统中有主,外键引用关系,并且满足一下三个条件中的任意一个,那么就应该考虑给外键字段创建索引,否则系统的性能可能会下降甚至阻塞。 
    (1) 主表上有频繁的删除操作 
    (2) 主键上有频繁的修改操作。 
    (3) 业务上经常会出现主表和从表做关联查询的情况。 
     
    第一和第二个条件操作的时候,主表会在从表上创建一个锁定,以保证主表主键的修改不会导致从表的数据在引用上出现问题,这是一个数据引用完整性的
    要求。  如果主表上经常出现这样的删除或者是对主键列进行修改的操作,或者每次操作的记录数很多,都将会造成从表长时间被锁定,而影响其他用户的正常
    操作。 比如主表每次删除1000行数据,它就需要扫描从表1000次,以确定每一行记录的改变都不会造成从表数据在引用上的不完整。  
       
      特别是在OLAP 系统中,从表经常会是非常巨大的表,在这种情况下,如果从表没有索引,那么查询几乎是不可想象的。 
    Latch是内存中的资源锁,数据库对象(表,索引等)的锁叫Lock。
    
    Latch和Lock的区别:
      (1). Latch 是对内存数据结构提供互斥访问的一种机制,而Lock是以不同
    的模式来套取共享资源对象,各个模式间存在着兼容或排斥,从这点看出,Latch
    的访问,包括查询也是互斥的,任何时候,只能有一个进程能pin住内存的某一
    块,幸好这个过程是相当的短暂,否则系统性能将没的保障,从9I开始,允许
    多个进程同时查询相同的内存块。
      (2). Latch 只作用于内存中,他只能被当前实例访问,而Lock作用于数据
    库对象,在RAC体系中实例间允许Lock检测与访问
      (3). Latch 是瞬间的占用,释放,Lock的释放需要等到事务正确的结束,
    他占用的时间长短由事务大小决定
      (4). Latch 是非入队的,而Lock是入队的
      (5). Latch 不存在死锁,而Lock中存在。 

    V$SESSION:  代表数据库活动的开始,视为源起。
    V$SESSION_WAIT:  视图用以实时记录活动SESSION的等待情况,是当前信
    息。
    V$SESSION_WAIT_HISTORY:  是对V$SESSION_WAIT的简单增强,记录活
    动SESSION的最近10次等待。
    V$SQLTEXT:  当数据库出现瓶颈时,通常可以从V$SESSION_WAIT找到那
    些正在等待资源的SESSION,通过SESSION 的SID,联合V$SESSION和
    V$SQLTEXT视图就可以捕获这些SESSION正在执行的SQL语句。
    V$ACTIVE_SESSION_HISTORY: 是ASH的核心,用以记录活动SESSION的历
    史等待信息,每秒采样一次,这部分内容记录在内存中,期望值是记录一个小时
    的内容。
    WRH#_ACTIVE_SESSION_HISTORY : 是V$ACTIVE_SESSION_HISTORY在
    AWR的存储地。  
    V$ACTIVE_SESSION_HISTORY: 中的信息会被定期(每小时一次)的刷新到负载
    库中,并缺省保留一个星期用于分析。
    DBA_HIST_ACTIVE_SESS_HISTORY:  视图是 WRH#_ACTIVE_SESSION_HISTORY视图和其他几个视图的联合展现,通常通
    过这个视图进行历史数据的访问。
    V$SYSTEM_EVENT  由于V$SESSION记录的是动态信息,和SESSION的生命
    周期相关,而并不记录历史信息,所以ORACLE提供视图V$SYSTEM_EVENT
    来记录数据库自启动以来所有等待事件的汇总信息。通过这个视图,用户可以迅
    速获得数据库运行的总体概况。

     来自书籍>>

  • 相关阅读:
    阿里云张新涛:连接产业上下游,构建XR协作生态
    从中间件到分布式数据库,PolarDBX的透明之路
    零信任策略下K8s安全监控最佳实践(K+)
    了解3D世界的黑魔法纯Java构造一个简单的3D渲染引擎
    EMR重磅发布智能运维诊断系统(EMR Doctor)——开源大数据平台运维利器
    PolarDBX拆分键推荐
    实战指南 | Serverless 架构下的应用开发
    【20220804】一定要遵守规则
    【20220810】给二宝取名
    【20220806】连岳摘抄
  • 原文地址:https://www.cnblogs.com/kingle-study/p/10729861.html
Copyright © 2020-2023  润新知