[English]
作者:
fuyuncat
来源:
www.HelloDBA.com
位图索引(Bitmap Index)是一种特殊索引。在普通B*树索引中,所有表数据记录指针都存储在叶子节点上,每一条非空数据在叶子节点上都存储一条记录,而非唯一索引中,同一键值对应多条记录在索引也存储多条记录,每条索引上都存储了对应表数据记录的物理地址,即ROWID。bitmap索引也是一个树状结构,但是每一个键值,无论是否为空、或者一个键对应多条数据记录,在叶子节点上只有一条记录,而对应的每一条表数据记录的物理地址通过映射函数转换,在索引记录中对应一个“位”(bit),所有对应记录的地址转换成“位”后形成一个位图(bitmap)存储在索引记录中。Bitmap索引不仅大大提高了重复值较多(Low Cardinality)的索引的查询效率——对应一个键值,只需读取一次就可以获取到所有表记录的物理地址,而普通索引可能需要读取多次索引后才能获取到全部数据,还减少了索引的存储空间。但是,由于一个键值对应多个数据记录,这就会造成数据更新的麻烦:当多个事务修改同一键值的数据时,都需要在对应的索引记录上加锁,从而导致事务等待:
SQL代码
- HELLODBA.COM>create bitmap index BITMAP_INDEX_DEMO_IDX on BITMAP_INDEX_DEMO (VALUE)
- 2 tablespace IDX_2K;
- Index created.
- --session 1:
- HELLODBA.COM>insert into BITMAP_INDEX_DEMO(value) values('A');
- 1 row created.
- --session 2:
- HELLODBA.COM>var v_val varchar2;
- HELLODBA.COM>exec :v_val := 'A';
- PL/SQL procedure successfully completed.
- HELLODBA.COM>insert into BITMAP_INDEX_DEMO(value) values(:v_val);
会话2被阻塞。
等待队列分析
这种情况的等待和我们之前分析的唯一性约束造成等待在属性上很相似:
它们请求的都是共享锁:
SQL代码
- HELLODBA.COM>select WAITING_SESSION, HOLDING_SESSION, MODE_HELD, MODE_REQUESTED from dba_waiters where lock_type='Transaction';
- WAITING_SESSION HOLDING_SESSION MODE_HELD MODE_REQUESTED
- --------------- --------------- ------------- --------------------------
- 302 289 Exclusive Share
等待事件为"enq: TX - row lock contention":
SQL代码
- HELLODBA.COM>select s.sid, s.event, s.row_wait_obj#, o.object_name
- 2 from v$session s, v$enqueue_lock l, dba_objects o
- 3 where l.sid = s.sid
- 4 and s.row_wait_obj# = o.object_id(+)
- 5 and s.sid =302;
- SID EVENT ROW_WAIT_OBJ# OBJECT_NAME
- ---------- -------------------------------- -------------- ----------------
- 302 enq: TX - row lock contention -1
因此,按照相同的方法排除其它可能(过程可以参考唯一性约束等待分析过程):
- 找到被阻塞的语句;
- 找到锁对象表;
- 找出对应表上的主外键约束、唯一约束和Bitmap索引。
如果仍然无法定位,则需要找到阻塞事务和被阻塞事务的逻辑代码进行分析。
死锁分析
对这一类等待导致的死锁的分析,也是要先确认锁的类型和等待事件类型:
SQL代码
- Deadlock graph:
- ---------Blocker(s)-------- ---------Waiter(s)---------
- Resource Name process session holds waits process session holds waits
- TX-0005002b-00023303 34 302 X 22 289 S
- TX-00060007-0001b390 22 289 X 34 302 S
- ...
- last wait for 'enq: TX - row lock contention' blocking sess=0x1EDC33AC seq=49 wait_time=2999978 seconds since wait started=624
- name|mode=54580004, usn<<16 | slot=60007, sequence=1b390
可以知道这是由于应用引起的死锁,然后获取相关语句进行逻辑分析:
SQL代码
- Current SQL statement for this session:
- insert into BITMAP_INDEX_DEMO(value) values(:v_val)
- ...
- Current SQL Statement:
- insert into BITMAP_INDEX_DEMO(value) values('B')
解决方法
同样的,由于这种等待或死锁是应用导致,其解决方法就是调整相关逻辑代码。
--- Fuyuncat TBC ---