Oracle位图索引引发的阻塞与死锁
来源:互联网 发布:黑客论坛数据库下载 编辑:程序博客网 时间:2024/06/14 14:07
转载自:http://blog.itpub.net/12330444/viewspace-619631/
前面我介绍了itl引发的阻塞与死锁,这里有必要再介绍一下位图索引引发的阻塞与死锁,因为这个也是不同于普通死锁的一种死锁方式,在有位图索引存在的表上面,其实很容易就引发阻塞与死锁。这个阻塞不是发生在表上面,而是发生在索引上。因为位图索引锁定的范围远远比普通的b-tree索引锁定的范围大。
假定,一个表,上面有标志字段(flags),分别是(0、1),而我们在这个flag字段上创建了一个位图索引,那么,现在我们执行如下的语句:
Piner@10gR2>update test set flags = 1 where id = 1;
假定id=1的的值原来是0,现在要更新成1,那么,这个语句在位图索引中,将锁住id=1那个记录所在的整个索引块中的flag=0与1的值,如果这个索引块中有很多记录,这个阻塞将是很严重的。另外注意,如果操作的dml不涉及到索引,则是不会被阻塞的。所以,在oltp环境中,如果一个表更新比较频繁,千万不要使用位图索引,如果数据仓库环境中,使用了位图索引,也最好在加载数据的时候将其删除,等数据加载完成以后重新创建。
我们看一个具体的例子
Piner@10gR2>select * from test; ID FLAG---------- ---------- 1 1 2 1 3 1 4 1 5 1 6 0 7 0 8 0 9 0 10 010 rows selected.
我们在上面创建一个位图索引
Piner@10gR2>create bitmap index ind_test on test(flag);Index created.
然后更新其中的一条记录,仅仅是一条记录
Piner@10gR2>update test set flag = 0 where id=1;1 row updated.
这个时候,其实整个位图都被锁定了(因为这些记录都在一个索引块中),我们看如下的例子,在另外的会话中,执行如下的语句可以发现:
Piner@10gR2>update test set flag = flag where id=6;1 row updated. Piner@10gR2>update test set flag = 1 where id=6; --blocked
可以发现第二个语句被阻塞
其实也就是说,如果不涉及到更新索引(因为第一次中,修改id=6的记录,flag值没有发生变化),那么就不会有阻塞的。当然,如果不是更新flag字段,而是其它字段,也不会有阻塞的,一旦涉及到修改flag的值,阻塞就发生了。
以上是是把0更新成1阻塞,那么把1更新成0同样阻塞
Piner@10gR2>update test set flag = flag where id=2;1 row updated.Piner@10gR2>update test set flag = 0 where id=2; --blocked
同样被阻塞
我们看看这个时候的等待原因,可以发现等待在TX锁上面
select EVENT from v$session_wait where sid=153EVENT-----------------------------enq: TX - row lock contention
理解了阻塞的原因,那么我们应当就很好理解位图死锁的原因了,数据行死锁差不多,2个进程互相锁住了资源,不同的是,行死锁抢的是同一样的数据,如同一行数据,位图索引死锁抢的是位图值,可以是不同的行。
接上面的表数据,我们模拟一个死锁,在会话1中执行如下命令
会话1
Piner@10gR2>update test set flag = 2 where id=1;1 row updated.
以上命令一旦发出,位图索引中锁住了所有flag=1(原值)以及flag=2(新值)的记录。
在会话2
Piner@10gR2>update test set flag = 3 where id=6;1 row updated.
这个命令锁住了所有flag=0(原值)以及flag=3(新值)的记录。
再回会话1,我们更新id=7的记录,注意,以上的操作记录都不相同。
Piner@10gR2>update test set flag = 2 where id=7; --blocked
结果是阻塞了,会话1等待会话2释放位图索引的锁定资源。
那么,我们在会话2中,再更新一条记录
Piner@10gR2>update test set flag = 3 where id=2; --blocked
虽然该记录与以上任何记录都不一样,也被阻塞了,等待会话1释放资源,到这里,死锁就形成了,马上可以看到,报了一个错在会话1上:
Piner@10gR2>update test set flag = 2 where id=7;update test set flag = 2 where id=7 *ERROR at line 1:ORA-00060: deadlock detected while waiting for resource
我们看跟踪文件,发现这里锁定的是索引,因为object_id=13009的对象就是是位图索引
Deadlock graph:
———Blocker(s)——– ———Waiter(s)———
Resource Name process session holds waits process session holds waits
TX-00050027-00001599 16 148 X 19 160 S
TX-00070014-00001579 19 160 X 16 148 S
session 148: DID 0001-0010-00000032 session 160: DID 0001-0013-00000004
session 160: DID 0001-0013-00000004 session 148: DID 0001-0010-00000032
Rows waited on:
Session 160: obj - rowid = 000032D1 - AAADLRAAAAAAAAAAAA
(dictionary objn - 13009, file - 0, block - 0, slot - 0)
Session 148: obj - rowid = 000032D1 - AAADLRAAAAAAAAAAAA
(dictionary objn - 13009, file - 0, block - 0, slot - 0)
第2楼 logzgh 于2007-05-23 16:21:55 Says:
“假定id=1的的值原来是0,现在要更新成1,那么,这个语句在位图索引中,锁住所有的flag为0以及flag为1的数据,这个是比较恐怖的。更新一行数据相当于锁定了整个索引”
你这里的说法不太正确。
事实上是锁定了id=1那条记录所在的索引块上所包含的所有记录。对大表来讲,一个索引块并不会包含所有的记录,所以不是整个索引。
第3楼 piner 于2007-05-23 19:33:04 Says:
“假定id=1的的值原来是0,现在要更新成1,那么,这个语句在位图索引中,锁住所有的flag为0以及flag为1的数据,这个是比较恐怖的。更新一行数据相当于锁定了整个索引”
你这里的说法不太正确。事实上是锁定了id=1那条记录所在的索引块上所包含的所有记录。对大表来讲,一个索引块并不会包含所有的记录,所以不是整个索引。
谢谢指正。。。这里我我有时间再实验一下。
第4楼 piner 于2007-05-23 20:16:03 Says:
现在发现,你的说法也不正确,你说锁住id=1的那个索引块,其实,我这里这么少的记录,应当就是一个索引块。
但是,下面的实验可以发现,set flag=2与flag=3是互相不等待的,也就是没有锁等待,按照你的说法,除非只是锁定了这个记录所在的索引块的flag = 新值 与 原值 的所有记录。
现在,我先这么改了,是否正确,我还要验证。
第5楼 piner 于2007-05-23 20:55:44 Says:
具体位图索引的内部,可以参考
http://www.itpub.net/showthread.php?threadid=743939
其实,锁定范围也可能不仅仅是一个索引块,9i与10g的变化也是比较大的,我们现在只要知道,锁定的范围比较大,不适合频繁修改的oltp即可。
- Oracle位图索引引发的阻塞与死锁
- 位图索引引发的阻塞与死锁
- ORACLE:由位图索引引发的sql问题
- oracle的位图索引
- Oracle位图索引与B-Tree索引的优缺点
- 外键缺少索引引发的死锁
- oracle中锁与死锁,还有阻塞的原因。
- [Oracle]B-树索引与位图索引
- 探讨Oracle 的位图索引
- oracle 位图索引的原理
- Oracle关于位图索引的创建与应用
- Oracle关于位图索引的创建与应用
- 一个阻塞队列引发的死锁和伪唤醒
- 一个由阻塞队列引发的类死锁案例
- SQL SERVER下非聚集索引引发的死锁问题
- Oracle 深入解析B-Tree索引与Bitmap位图索引的锁代价
- Oracle中B-Tree索引与Bitmap位图索引的锁代价比较研究
- oracle锁与死锁概念,阻塞产生的原因以及解决方案
- gcc 连接与汇编,连接的对比
- 安卓如何加载GIF图片
- javascript 使用btoa和atob来进行Base64转码和解码
- 管理系统UI之四:使用全屏沉浸模式(Using Immersive Full-Screen Mode)
- 插件GsonFormat快速实现JavaBean
- Oracle位图索引引发的阻塞与死锁
- java细节之null == 和 ==null
- bzoj 2705: [SDOI2012]Longge的问题 欧拉函数
- 云帮系列文章:技术架构说明
- MTK RIL 调试方式
- 227. Basic Calculator II
- 管理系统UI之五:响应UI可见性的变化(Responding to UI Visibility Changes)
- 【总结】软件工程视频
- Python字符串匹配存在的问题