1,enq: TX- index contention等待事件的概念
2,如何产生此等待事件
3,如何解决等待事件
4,小结
.

1,enq: TX- index contention等待事件的概念
      1,当在基于索引的表中插入一条记录时,此时正好另一会话事务正在操作这个索引块正处于分裂状态(即索引块分裂)
    
    
    
    
    
    
2,如何产生此等待事件

--构造等待事件 enq: TX- index contention,如高并发引发此事件
--并发job
declare
v_job pls_integer;
begin
for i in 1..100 loop
dbms_job.submit(v_job,what => 'proc_arg;',next_date => sysdate,interval=>'sysdate+1');
commit;
end loop;
end;
/

--并发job调用的存储过程
create or replace procedure proc_arg
as
begin
 insert into t_detail values(1);
 --dbms_lock.sleep(120);
--commit;
end;        

--查询是否发生了enq: TX- index contention事件
--先温习下v$session_wait视图几个重要列的含义:
 1,WAIT_TIME_MICRO,
      1,单位为毫秒
      2,如当前会话处于等待,则为已等待占用的时间
      3,如当前会话已停止等待,则为最近一次等待占用的时间
 2,TIME_REMAINING_MICRO
      1,本参数有几类值
      2,若值>0,则表示还要等待多久时间
        若值=0,则表示当前会话已超时
        若值=-1,则表示不知还要等待多久
        若值=null,表示当前会话未处于等待状态

--由下可知,不知还要等多久
SQL> select event,WAIT_TIME_MICRO,TIME_REMAINING_MICRO from v$session_wait where event like '%enq: TX - index contention%';
 
EVENT                                                            WAIT_TIME_MICRO TIME_REMAINING_MICRO
---------------------------------------------------------------- --------------- --------------------
enq: TX - index contention                                                804411                   -1
enq: TX - index contention                                                804144                   -1
enq: TX - index contention                                                821468                   -1
enq: TX - index contention                                                759771                   -1
enq: TX - index contention                                                766228                   -1
--中间略
enq: TX - index contention                                                784128                   -1

--判断上述的enq: TX - index contention是否和索引块分裂有关
SQL> select * from v$event_name where name like '%split%';
 
    EVENT#   EVENT_ID NAME                                                             PARAMETER1                                                       PARAMETER2                                                       PARAMETER3                                                       WAIT_CLASS_ID WAIT_CLASS# WAIT_CLASS
---------- ---------- ---------------------------------------------------------------- ---------------------------------------------------------------- ---------------------------------------------------------------- ---------------------------------------------------------------- ------------- ----------- ----------------------------------------------------------------
       169 1457266432 gc current split                                                                                                                                                                                                                                                       3871361733          11 Cluster
       769   67546339 index block split                                                rootdba                                                          level                                                            childdba                                                            1893977003           0 Other
       794  695862004 kksscl hash split                                                                                                                                                                                                                                                      1893977003           0 Other
       994 1569316226 enq: AM - PST split check                                        name|mode                                                        id1                                                              id2                                                                 1893977003           0 Other
 
SQL> select sid,event,total_waits,average_wait from v$session_event where event in (select name from v$event_name where name like '%split%' and event#=769);
 
       SID EVENT                                                            TOTAL_WAITS AVERAGE_WAIT
---------- ---------------------------------------------------------------- ----------- ------------
 

--未看到索引块分裂
 SQL> select sid,event,total_waits,average_wait from v$session_event where event like '%index%'
 
       SID EVENT                                                            TOTAL_WAITS AVERAGE_WAIT
---------- ---------------------------------------------------------------- ----------- ------------
        10 enq: TX - index contention                                                34        74.76
        14 enq: TX - index contention                                               101       112.85
        15 enq: TX - index contention                                                90        74.66
---中间内容略
        17 enq: TX - index contention                                                17        63.72
        20 enq: TX - index contention                                               101        64.37
       170 enq: TX - index contention                                               107        74.87
       171 enq: TX - index contention                                               107         66.2
       172 enq: TX - index contention                                                 3        63.76
 
59 rows selected


SQL> select * from v$event_name where name like '%enq%index%';
NAME                                                             PARAMETER1                                                       PARAMETER2                                                       PARAMETER3                                                         WAIT_CLASS
---------------------------------------------------------------- ---------------------------------------------------------------- ---------------------------------------------------------------- ----------------------------------------------------------------   ----------------------------------------------------------------
enq: TX - index contention                                       name|mode                                                        usn<<16 | slot                                                   sequence                                                           Concurrency
 
--获取与索引块分裂的统计
SQL> select * from v$sesstat where rownum=1;
 
       SID STATISTIC#      VALUE
---------- ---------- ----------
         1          0          0
 
SQL> select * from v$statname where name like '%split%';
 
STATISTIC# NAME                                                                  CLASS    STAT_ID
---------- ---------------------------------------------------------------- ---------- ----------
       382 leaf node splits                                                        128 1417124053
       383 leaf node 90-10 splits                                                  128 1285138251
       384 branch node splits                                                      128  399027615
       385 root node splits                                                        128  708722985
       400 queue splits                                                            128 1168925905
 
--叶子块分裂的统计信息 
SQL> select sum(ss.VALUE)  from v$sesstat ss,v$statname st where ss.STATISTIC#=st.statistic# and st.statistic#=382;
 
SUM(SS.VALUE)
-------------
            3 
           
--运行并发会话后叶子块分裂的情况,确实发生了叶子块分裂           
SQL> select sum(ss.VALUE)  from v$sesstat ss,v$statname st where ss.STATISTIC#=st.statistic# and st.statistic#=382;
 
SUM(SS.VALUE)
-------------
          437
 
SQL> /
 
SUM(SS.VALUE)
-------------
          591
         
         
3,如何解决等待事件
  1,重构索引,建立反向键索引
  2,增大索引的pctfree
 
  --查看index的pctfree
  SQL> select pct_free from user_indexes where index_name='IDX_T_DETAIL';
 
  PCT_FREE
----------
        10
 
  --可删除索引创建反向键索引     
  SQL> create index idx_t_detail on t_detail(a) reverse;
 
  Index created
 
  --反向键索引有了,是否会降低enq: TX - index contention竞争呢
 
  --enq: TX - index contention等待事件还有;total_waits表示等待次数;average_wait表示平均每次等待多久时间,单位为in hundredths of a second
  --但这个v$session_event不会保存下来,等待事件一结束就看不到了,主要想看平均等待事件,在dba_hist也没找到相应的表
  select sid,event,total_waits,average_wait from v$session_event where event like 'enq: TX - index contention';
  ---------- ---------------------------------------------------------------- ----------- ------------
         8 enq: TX - index contention                                                58        62.29
        18 enq: TX - index contention                                                86        82.81
        19 enq: TX - index contention                                                89        69.25
        29 enq: TX - index contention                                               112        72.57
        38 enq: TX - index contention                                               114        72.14
        55 enq: TX - index contention                                               107        69.71
        61 enq: TX - index contention                                               111        66.13
       
--如下视图可以查询上述等待事件的变动信息,根据事件分类,并根据等待事件长短分为不同的桶,桶的标准为:
--from < 1 ms, < 2 ms, < 4 ms, < 8 ms, ... < 221 ms, < 222 ms, and >= 222 ms.       
select  event ,
        wait_time_milli,
        wait_count,
        last_update_time
from V$EVENT_HISTOGRAM
where event like 'enq: TX - index contention';  

--此为上述的历史信息
SQL> select * from dba_hist_event_histogram where event_name like 'enq: TX - index contention';  

--我的思路通过运行b-tree index与反向键index,比对V$EVENT_HISTOGRAM上述的结果,有何区别

--v$event_histogram不会自动清除结果,须重启库方可(在此为了对比)

--为了对比,先删除之前的索引
SQL> drop index idx_t_detail;
 
Index dropped

--创建b-tree index
SQL> create index idx_t_detail on t_detail(a);
 
Index created

--运行文章前面的并发plsql脚本

--交替运行下面2个脚本,此脚本确保上述的并发plsql脚本运行完毕
SQL> select count(1) from v$session_event where event like 'enq: TX - index contention';
 
  COUNT(1)
----------
         1
        
        
--查看等待事件的统计信息
SQL> select  event ,
  2          wait_time_milli,
  3          wait_count,
  4          last_update_time
  5  from V$EVENT_HISTOGRAM
  6  where event like 'enq: TX - index contention';
 
EVENT                                                            WAIT_TIME_MILLI WAIT_COUNT LAST_UPDATE_TIME
---------------------------------------------------------------- --------------- ---------- -------------------------------------------------------------------------
enq: TX - index contention                                                     1        159 18-MAR-13 04.41.39.178979 PM +08:00
enq: TX - index contention                                                     2         45 18-MAR-13 04.41.41.478856 PM +08:00
enq: TX - index contention                                                     4         58 18-MAR-13 04.41.38.528987 PM +08:00
enq: TX - index contention                                                     8         56 18-MAR-13 04.41.41.183837 PM +08:00
enq: TX - index contention                                                    16         97 18-MAR-13 04.41.37.391778 PM +08:00
enq: TX - index contention                                                    32        163 18-MAR-13 04.41.41.606186 PM +08:00
enq: TX - index contention                                                    64        289 18-MAR-13 04.41.41.372071 PM +08:00
enq: TX - index contention                                                   128        485 18-MAR-13 04.41.40.770750 PM +08:00
enq: TX - index contention                                                   256        654 18-MAR-13 04.41.39.239939 PM +08:00
enq: TX - index contention                                                   512       1185 18-MAR-13 04.41.40.940983 PM +08:00
enq: TX - index contention                                                  1024       1864 18-MAR-13 04.41.38.830764 PM +08:00
enq: TX - index contention                                                  2048        876 18-MAR-13 04.41.40.670356 PM +08:00
enq: TX - index contention                                                  4096        152 18-MAR-13 04.41.09.104519 PM +08:00
enq: TX - index contention                                                  8192         23 18-MAR-13 04.39.27.721987 PM +08:00
enq: TX - index contention                                                 16384         12 18-MAR-13 04.39.20.452465 PM +08:00
enq: TX - index contention                                                 32768         14 18-MAR-13 04.39.47.426106 PM +08:00


--重启库为了清除v$event_histogram的统计信息,再看看反向键索引的竞争情况
EVENT                                                            WAIT_TIME_MILLI WAIT_COUNT LAST_UPDATE_TIME
---------------------------------------------------------------- --------------- ---------- -------------------------------------------------------------------------
enq: TX - index contention                                                     1        136 18-MAR-13 05.11.10.278219 PM +08:00
enq: TX - index contention                                                     2         35 18-MAR-13 05.11.10.243922 PM +08:00
enq: TX - index contention                                                     4         43 18-MAR-13 05.11.09.834354 PM +08:00
enq: TX - index contention                                                     8         60 18-MAR-13 05.11.07.219909 PM +08:00
enq: TX - index contention                                                    16         74 18-MAR-13 05.11.08.621526 PM +08:00
enq: TX - index contention                                                    32        135 18-MAR-13 05.11.10.028352 PM +08:00
enq: TX - index contention                                                    64        311 18-MAR-13 05.11.09.444585 PM +08:00
enq: TX - index contention                                                   128        485 18-MAR-13 05.11.09.972510 PM +08:00
enq: TX - index contention                                                   256        669 18-MAR-13 05.11.09.793868 PM +08:00
enq: TX - index contention                                                   512       1130 18-MAR-13 05.11.06.987832 PM +08:00
enq: TX - index contention                                                  1024       1932 18-MAR-13 05.11.09.289674 PM +08:00
enq: TX - index contention                                                  2048       1128 18-MAR-13 05.11.05.031096 PM +08:00
enq: TX - index contention                                                  4096        166 18-MAR-13 05.10.37.715998 PM +08:00
enq: TX - index contention                                                  8192          8 18-MAR-13 05.08.37.833097 PM +08:00
enq: TX - index contention                                                 16384          5 18-MAR-13 05.08.37.820380 PM +08:00    


结论:反向键索引的竞争反而更多了,我是算的上面的累计值

--看来还有问题,要么不能用反向键,要么我测试的方法不对:

--既然与索引块分裂有关,如果加大索引所在数据块大小,会不会减少竞争次数呢

--使用大数据块必备配置
SQL> alter system set db_16k_cache_size=20m scope=spfile;
 
System altered

--创建大数据表空间
SQL> create tablespace tbs_16k datafile
  2  'c:\tbs16k_1.dbf' size 2g blocksize 16k;
 
Tablespace created

--切换索引到大数据块表空间
SQL> select index_name,tablespace_name from user_indexes where index_name='IDX_T_DETAIL';
 
INDEX_NAME                     TABLESPACE_NAME
------------------------------ ------------------------------
IDX_T_DETAIL                   TBS_HANG
 
SQL> alter index idx_t_detail rebuild tablespace tbs_16k;
 
Index altered
 
SQL> select index_name,tablespace_name from user_indexes where index_name='IDX_T_DETAIL';
 
INDEX_NAME                     TABLESPACE_NAME
------------------------------ ---------
IDX_T_DETAIL                   TBS_16K

--大数据块测试的竞争如下
EVENT                                                            WAIT_TIME_MILLI WAIT_COUNT LAST_UPDATE_TIME
---------------------------------------------------------------- --------------- ---------- -------------------------------------------------------------------------
enq: TX - index contention                                                     1        106 18-MAR-13 08.01.30.221162 PM +08:00
enq: TX - index contention                                                     2         30 18-MAR-13 08.01.25.504420 PM +08:00
enq: TX - index contention                                                     4         25 18-MAR-13 08.01.25.506781 PM +08:00
enq: TX - index contention                                                     8         39 18-MAR-13 08.01.29.690659 PM +08:00
enq: TX - index contention                                                    16         77 18-MAR-13 08.01.29.691672 PM +08:00
enq: TX - index contention                                                    32        100 18-MAR-13 08.01.10.861044 PM +08:00
enq: TX - index contention                                                    64        236 18-MAR-13 08.01.19.586879 PM +08:00
enq: TX - index contention                                                   128        293 18-MAR-13 08.01.30.129016 PM +08:00
enq: TX - index contention                                                   256        423 18-MAR-13 08.01.29.552920 PM +08:00
enq: TX - index contention                                                   512        477 18-MAR-13 08.01.30.955651 PM +08:00
enq: TX - index contention                                                  1024        681 18-MAR-13 08.01.24.291290 PM +08:00
enq: TX - index contention                                                  2048        628 18-MAR-13 08.01.27.361559 PM +08:00
enq: TX - index contention                                                  4096        252 18-MAR-13 08.01.27.762065 PM +08:00
enq: TX - index contention                                                  8192         48 18-MAR-13 08.01.05.489611 PM +08:00
enq: TX - index contention                                                 16384         10 18-MAR-13 07.59.39.765070 PM +08:00
 
15 rows selected         


--加大数据块尺寸后,index contention大大减少

--哪么修改index pctfree效果表现如何呢

----修改前的pctfree
SQL> select pct_free from user_indexes where index_name='IDX_T_DETAIL';
                                                                      
  PCT_FREE                                                            
----------                                                            
        10     
--有个问题要搞清楚,oracle在插入索引块时,是先在每个已有数据的索引块先查找是否有符合条件的空闲数据块,还是直接查找一个新的索引块

pctfree--为每个数据保留一个用于后来update的比例;减小此参数会不会减少index contention

SQL> drop index idx_t_detail;
 
Index dropped
 
SQL> create index idx_t_detail on t_detail(a) tablespace tbs_16k pctfree 0;
 
Index created       
                   
--贴上pctfree为0的index contention,可知竞争大为减少;                   
---------------------------------------------------------------- --------------- ---------- -------------------------------------------------------------------------                                                                                                                                                                                                                                                                                                                                                                                 
enq: TX - index contention                                                     1         63 18-MAR-13 08.54.42.786397 PM +08:00                                     
enq: TX - index contention                                                     2          9 18-MAR-13 08.54.37.646487 PM +08:00                                     
enq: TX - index contention                                                     4         12 18-MAR-13 08.54.37.053155 PM +08:00                                     
enq: TX - index contention                                                     8          7 18-MAR-13 08.54.40.311190 PM +08:00                                     
enq: TX - index contention                                                    16         26 18-MAR-13 08.54.42.766359 PM +08:00                                     
enq: TX - index contention                                                    32         30 18-MAR-13 08.54.42.667444 PM +08:00                                     
enq: TX - index contention                                                    64         47 18-MAR-13 08.54.42.755426 PM +08:00                                     
enq: TX - index contention                                                   128         63 18-MAR-13 08.54.37.625092 PM +08:00                                     
enq: TX - index contention                                                   256         98 18-MAR-13 08.54.40.562709 PM +08:00                                     
enq: TX - index contention                                                   512        109 18-MAR-13 08.54.40.364472 PM +08:00                                     
enq: TX - index contention                                                  1024        138 18-MAR-13 08.54.42.479061 PM +08:00                                     
enq: TX - index contention                                                  2048        186 18-MAR-13 08.54.42.478623 PM +08:00                                     
enq: TX - index contention                                                  4096        109 18-MAR-13 08.54.27.103869 PM +08:00                                     
enq: TX - index contention                                                  8192         41 18-MAR-13 08.54.27.108269 PM +08:00                                     
enq: TX - index contention                                                 16384         12 18-MAR-13 08.54.01.466532 PM +08:00                                     
                  
                  
4,小结
   1,如出现enq: TX - index contention,说明此时正有会话正在操作分裂的索引块,而你所属会话要更新此数据块则发生此事件
   2,高并发会产生此事件                                                                                                                                                                    
   3,把索引和表存储在独立的表空间,加大索引的block size(注意:其它附加副作用,暂未测试)
   4,重构索引为反向键索引或全局hash index,说白了就是把索引块打散分布到多个数据块,不要集中存储;这样每个块竞争的机会就减少
   5,修正index pctfree为0,大大减少index contention, 但要注意表是否只能insert,如还伴随大量的update(此块下文研究)