• oracle 10g create index online 在基表上的表级锁加锁过程


    在Oracle10g上在线创建索引时,会话在基表上的表级锁加锁过程如下:

    1、会话在基表上加RS(2)锁。此时基表上已经在运行的DML操作不受影响,新的DML操作也可以开始。

    2、会话在取得RS锁后,迅速请求将该锁转换成S(4)锁。由于S锁与RX锁不相容,如果此时基表上有DML操作(已有事务)在运行,创建索引的会话将不得不一直等待直到已有的DML操作完成(回滚或提交)才能取得S锁。在创建索引的会话申请S锁之后开始的DML操作(新事务)将一直处于等待状态,直到创建索引的会话释放S锁为止。表级锁采用的是一种类似队列的处理机制,创建索引的会话申请的S锁排在新事务的RS锁之前,因此即使新事务的RS锁与老事务的RS锁相容,也只能等待S锁处理完成才能获得。如果在创建索引之前基表上有长时间运行的大事务,创建索引的会话需要长时间等待,同时造成新事务也处于长时间等待状态,这对于具有较大压力的OLTP系统来说具有非常大的风险。

    3、会话取得S锁后,迅速请求将该锁转换成RS(2)锁,该转换会立即成功。取得RS锁后,会话开始对基表进行全表扫描并创建索引,全表扫描读取的数据是S锁获取成功时刻的数据。此处采用的机制类似于读一致性。而在创建索引过程中,新事务不受影响,新事务的DML操作会记录到JOURNAL表中。

    4、会话一直持有RS锁直到基表索引创建完,将JOURNAL表数据合并到新建索引阶段。然后会话请求将锁转换成S(4)锁。同步骤2类似,如果此时基表上有DML操作(已有事务)在运行,创建索引的会话将不得不一直等待直到已有的DML操作完成(回滚或提交)才能取得S锁。而新事务也将处于等待状态,直到S锁释放。会话取得S锁后,将一直持有该锁直到数据合并完成。如果在创建索引的会话请求S锁时,基表上的大事务在运行,会造成新事务长时间等待。同样,如果在索引创建过程中,基表产生了大量DML操作,此时会有大量数据需要合并,这势必会增加数据合并时间,造成会话长时间持有S锁,进而导致新事务长时间等待。此阶段对于具有较大压力的OLTP系统来说风险很大。

    下面通过实验测试加锁过程。此处使用的是Saibabu Devabhaktuni(http://sai-oracle.blogspot.com)的测试脚本。

    • 在session 1中创建测试表和函数:

    scott@ora10g: SQL> create table oib1 as select rownum a, rownum b from dual connect by level <= 101;

    Table created.

    scott@ora10g: SQL> create or replace function oib_f(a1 in number) return number deterministic as
      2  begin
      3  if (a1 = 100) then
      4  sys.dbms_lock.sleep(120);
      5  end if;
      6  return a1;
      7  end;
      8  /

    Function created.

    scott@ora10g: SQL> select distinct sid from v$mystat;

           SID
    ----------
           138

    • 另开一个session 2:

    scott@ora10g: SQL> select distinct sid from v$mystat;

           SID
    ----------
           139

    scott@ora10g: SQL> set time on
    22:34:01 scott@ora10g: SQL> insert into oib1 values (1,1);

    1 row created.

    22:34:08 scott@ora10g: SQL> select sid, type, id1, id2, lmode, request, block from v$Lock where type='TM';

           SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
    ---------- -- ---------- ---------- ---------- ---------- ----------
           139 TM      17112          0          3          0          0

    此时session2的会话139在测试表上持有RX锁。

    • 回到session 1:

    scott@ora10g: SQL> set time on
    22:34:36 scott@ora10g: SQL> alter session set events '10704 trace name context forever, level 12';

    Session altered.

    设置10704事件来trace创建索引时的加锁情况。

    22:34:44 scott@ora10g: SQL> create index oib1_idx on oib1(oib_f(a)) online;

    create index语句处于等待状态,直到session 2中的事务完成后。此时如果基表上有新DML操作,新DML操作也将处于等待状态。

    • 回到session 2检查表上的加锁情况:

    22:35:21 scott@ora10g: SQL> select sid, type, id1, id2, lmode, request, block from v$Lock where type='TM';

           SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
    ---------- -- ---------- ---------- ---------- ---------- ----------
           139 TM      17112          0          3          0          1
           138 TM      17112          0          2          4          0
           138 TM      17114          0          4          0          0

    session2(139)持有测试表上的RX锁,而session1(138)持有测试表上的RS锁,同时申请S锁。由于S锁与RX锁不相容,session1处于等待状态。注意object 17114实际上是JOURNAL表。session 1在JOURNAL表上持有S锁。

    22:39:31 scott@ora10g: SQL> rollback;

    Rollback complete.

    等待约5分钟后,回滚insert语句,session 2将释放测试表上的RX锁。

    22:39:40 scott@ora10g: SQL> select sid, type, id1, id2, lmode, request, block from v$Lock where type='TM';

           SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
    ---------- -- ---------- ---------- ---------- ---------- ----------
           138 TM      17112          0          2          0          0
           138 TM      17114          0          4          0          0

    此时session2(139)已经释放了测试表上的RX锁,session 1(138)在获得S锁后,很快将该锁又转换成RS锁。然后session 1开始创建基表的索引,session1利用一致性读来扫描基表,读取的是基表获得S锁时刻的一致性数据。

    • 新开session 3, 在基表上执行DML操作:

    scott@ora10g: SQL> select distinct sid from v$mystat;

           SID
    ----------
           146

    scott@ora10g: SQL> set time on
    22:40:03 scott@ora10g: SQL> insert into oib1 values (2,2);

    1 row created.

    在索引开始创建后执行DML操作,此时的DML操作将记入JOURNAL表。在最后阶段合并到基表索引中。

    22:40:09 scott@ora10g: SQL> select sid, type, id1, id2, lmode, request, block from v$Lock where type='TM';

           SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
    ---------- -- ---------- ---------- ---------- ---------- ----------
           146 TM      17112          0          3          0          0
           138 TM      17112          0          2          0          0
           138 TM      17114          0          4          0          0

    session 1(138)在基表上加RS锁,session 3(146)在基表上加RX锁。在数据合并阶段,session1将申请基表上的S锁。

    22:40:18 scott@ora10g: SQL> select object_name,object_type from dba_objects where object_id=17114;

    OBJECT_NAME               OBJECT_TYPE
    -----------------         -------------
    SYS_JOURNAL_17113         TABLE

    object 17114是JOURNAL表。

    22:42:24 scott@ora10g: SQL> select sid, type, id1, id2, lmode, request, block from v$Lock where type='TM';

           SID TY        ID1        ID2      LMODE    REQUEST      BLOCK
    ---------- -- ---------- ---------- ---------- ---------- ----------
           146 TM      17112          0          3          0          1
           138 TM      17112          0          2          4          0
           138 TM      17114          0          4          0          0

    session 1(138)在数据合并阶段对基表请求S锁,处于等待状态。

    22:43:56 scott@ora10g: SQL> rollback;

    Rollback complete.

    等待约几钟后,回滚insert.

    22:45:01 scott@ora10g: SQL>

    • 回到session 1:

    创建索引的操作很快完成。

    22:45:01 scott@ora10g: SQL> alter session set events '10704 trace name context off';

    Session altered.

    scott@ora10g: SQL> select object_name,object_type from dba_objects where object_id=17112;

    OBJECT_NAME          OBJECT_TYPE
    -------------------- --------------------
    OIB1                 TABLE

    object 17112是测试表OIB1.

    scott@ora10g: SQL> select to_char(17112,'xxxxx') from dual;

    TO_CHA
    ------
      42d8

    把17112转换成16进制数。
     

    以下是trace文件中的信息。
    *** 2012-06-15 22:34:51.633
    ksqgtl *** DL-000042d8-00000000 mode=3 flags=0x11 timeout=0 ***  -->先请求模式为3类型的DL锁
    ksqgtl: xcb=0x38f85e518, ktcdix=2147483647, topxcb=0x38f85e518
            ktcipt(topxcb)=0x0
    *** 2012-06-15 22:34:51.633
    ksucti: init txn DID from session DID 0001-0017-0000000B
    ksqgtl:
            ksqlkdid: 0001-0017-0000000B
    *** 2012-06-15 22:34:51.634
    *** ksudidTrace: ksqgtl
            ktcmydid(): 0001-0017-0000000B
            ksusesdi:   0000-0000-00000000
            ksusetxn:   0001-0017-0000000B
    ksqgtl: RETURNS 0      -->请求很快完成
    *** 2012-06-15 22:34:51.634
    ksqgtl *** DL-000042d8-00000000 mode=3 flags=0x11 timeout=0 *** -->再请求模式为3类型的DL锁
    ksqgtl: xcb=0x38f85e518, ktcdix=2147483647, topxcb=0x38f85e518
            ktcipt(topxcb)=0x0
    *** 2012-06-15 22:34:51.634
    ksucti: init session DID from txn DID: 0001-0017-0000000B
    ksqgtl:
            ksqlkdid: 0001-0017-0000000B
    *** 2012-06-15 22:34:51.634
    *** ksudidTrace: ksqgtl
            ktcmydid(): 0001-0017-0000000B
            ksusesdi:   0000-0000-00000000
            ksusetxn:   0001-0017-0000000B
    *** 2012-06-15 22:34:51.634
    ksqcmi: DL,42d8,0 mode=3 timeout=0
    ksqcmi: returns 0
    ksqgtl: RETURNS 0   -->请求很快完成

    *** 2012-06-15 22:34:51.634
    ksqgtl *** TM-000042d8-00000000 mode=2 flags=0x401 timeout=21474836 ***  -->在基表上请求RS锁
    ksqgtl: xcb=0x38f85e518, ktcdix=2147483647, topxcb=0x38f85e518
            ktcipt(topxcb)=0x0
    *** 2012-06-15 22:34:51.634
    ksucti: init session DID from txn DID: 0001-0017-0000000B
    ksqgtl:
            ksqlkdid: 0001-0017-0000000B
    *** 2012-06-15 22:34:51.634
    *** ksudidTrace: ksqgtl
            ktcmydid(): 0001-0017-0000000B
            ksusesdi:   0000-0000-00000000
            ksusetxn:   0001-0017-0000000B
    *** 2012-06-15 22:34:51.634
    ksqcmi: TM,42d8,0 mode=2 timeout=21474836
    ksqcmi: returns 0
    ksqgtl: RETURNS 0 -->请求很快完成,获得RS锁
    ......
    *** 2012-06-15 22:34:51.662 -->22:34:51.662-22:34:51.634 =0.028秒
    ksqcnv: TM-000042d8,00000000 mode=4 timeout=21474836 -->很快请求将RS锁convert成S锁

    *** 2012-06-15 22:34:51.662
    ksqcmi: TM,42d8,0 mode=4 timeout=21474836
    *** 2012-06-15 22:39:40.694 -->convert花费了约5分钟(22:39:40.694 -22:34:51.662)才完成。这是因为session 2持有RX锁,
    ksqcmi: returns 0                    -->session1 convert一直等待。session2 rollback后,session 1才conver完成。
    ksqcnv: RETURNS 0 -->convert成功
    *** 2012-06-15 22:39:40.694
    ksqcnv: TM-000042d8,00000000 mode=2 timeout=21474836  -->获得S锁后,立即(22:39:40.694-22:39:40.694)请求将S锁
    *** 2012-06-15 22:39:40.694                                              -->convert成RS锁,并且covert立即成功。
    ksqcmi: TM,42d8,0 mode=2 timeout=21474836
    ksqcmi: returns 0
    ksqcnv: RETURNS 0                                                              -->convert成功,开始创建索引
    ......
    *** 2012-06-15 22:41:40.704 -->22:41:40.704-22:39:40.694=2分钟
    ksqcnv: TM-000042d8,00000000 mode=4 timeout=21474836 -->约2分钟后(函数sleep时间,表数据量很小,索引创建时间可忽略)
    *** 2012-06-15 22:41:40.704 -->请求将RS锁convert成S锁
    ksqcmi: TM,42d8,0 mode=4 timeout=21474836
    *** 2012-06-15 22:45:01.046      -->约3分钟后(22:45:01.046-22:41:40.704),才convert成功。因为session3持有RX锁,
    ksqcmi: returns 0 -->session1一直处于等待状态。session3回滚后,session1才convert成功。
    ksqcnv: RETURNS 0                   -->convert成功。
    ......
    *** 2012-06-15 22:45:01.062   
    ksqrcl: DL,42d8,0                        -->应该是release DL锁
    ksqrcl: returns 0
    *** 2012-06-15 22:45:01.062
    ksqrcl: DL,42d8,0                        -->再release DL锁
    ksqrcl: returns 0
    ......
    *** 2012-06-15 22:45:01.080
    ksqrcl: TM,42d8,0                      -->release TM锁。从取得S锁到releasse锁的时间很短(22:45:01.080 -22:45:01.046)
    ksqrcl: returns 0 -->这个时间应该是与需要merge的数据量直接相关。

    在Oracle10g中rebuild index online与create index online的操作过程一样,加锁过程也一样,都是通过全表扫描来建立索引

    以下是用explain plan看到的rebuild index online执行计划:

    scott@ora10g: SQL> explain plan for alter index OIB1_IDX rebuild online;

    Explained.
    scott@ora10g: SQL> select * from table(dbms_xplan.display);

    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------
    Plan hash value: 2031255143

    -----------------------------------------------------------------------------------
    | Id  | Operation              | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------
    |   0 | ALTER INDEX STATEMENT  |          |   101 |   808 |     3   (0)| 00:00:01 |
    |   1 |  INDEX BUILD NON UNIQUE| OIB1_IDX |       |       |            |          |
    |   2 |   SORT CREATE INDEX    |          |   101 |   808 |            |          |
    |   3 |    TABLE ACCESS FULL   | OIB1     |   101 |   808 |     3   (0)| 00:00:01 |
    -----------------------------------------------------------------------------------

  • 相关阅读:
    期待Eclipse3.4
    Winforms中使用系统托盘图标
    Eclipse下的Struts2开发插件
    彩色 夺冠
    网络&系统
    A Famous Music Composer
    Quick Brown Fox
    解密QQ号——队列
    谁先倒
    bootstrap Table从零开始
  • 原文地址:https://www.cnblogs.com/cqubityj/p/2551947.html
Copyright © 2020-2023  润新知