Rexdf

The devil is in the Details.

对于Oracle锁的一些理论总结

| Comments

首先什么是锁呢?可以理解为他是对一种共享资源并发访问的一种控制:) 在数据库中,基本的锁类型有两类,分别是 X-排他锁:如果对象被一个排他锁给琐住,那么按照锁的相容性来讲其他会话就不能够在对这个会话所加锁的对象加任何的锁。 S-共享锁:如果对象被一个共享锁给锁住,那么按照锁的相容性来讲其他会话除了S锁本身,都不能对这个会话所加锁的对象加任何的锁。 那么在Oracle数据库中呢,锁是多粒度的,而且他的锁类型可以分三大类 1.DML lock:目的是为了保护数据完整性 2.DDL lock:目的是为了保护数据库对象的结构 3.一些内部锁和latch:目的是为了保护数据库的内部结构 这里呢,主要想介绍一下DML锁,因为其他类型的锁基本上只会保持很短的一段时间 DML锁呢共有两种 1.row level lock  2.table level lock 1.TX(row level lock) 先 介绍一下行级锁吧,其实很多人都认为在数据库中,行级锁就是锁定一行(注意我想说Oracle在数据行上面只有排他锁X,而没有共享锁之类的其他锁)。很 多朋友认为一个数据表里有多少行,就会有多少个行级别锁,在Oracle却不是这样,其实需要澄清的是,Oracle对于行级锁是事务级的。也就是说当一 个事务发起一个更新(update)命令时,无论事务所涉及的行有多少,那么Oracle只会分配一个TX锁,所以在这里Oracle是不会像其他数据库 一样有锁的升级(lock escalation),而且这中锁升级也并不是数据库的特性,但是他会执行锁的转换,Oracle会尽可能的在最低级别加锁。因此对于开销来讲1个锁的 开销和1000000个锁的开销其实是一样的,都没有什么开销。而且Oracle也不会像其他数据库一样来通过维护一个锁的列表来管理锁的资源(比如 DB2,通过LOCKLIST,MAXLOCKS两个参数来度量锁的开销),因为对于DB2来说,锁是一种稀有的资源,需要对锁的使用呢,进行监控,系统 开销就必然很大,而Oracle在锁的维护上就大大的减少了开销,而且也不会出现因为锁数量不够时引起的问题(锁升级->死锁). 让我们来对比一下DB2和Oracle在行级的加锁过程 DB2 -—– 加锁的时候 1,找到想锁定那一行的地址 2.在locklist中排队(其实这种锁管理器就是一种串行化的设备,这样做的好处是可以有效的避免活锁) 3.锁定列表 4.搜索列表,看看别人是否已经对我要加锁的那一样上了锁 5,如果没有,则在列表中创建一个entry,表明我已经锁住了这一行 6.对列表解锁 解锁的时候 1.再次进行排队 2.锁住我们的列表 3.在这个列表中搜索,释放我们的锁 4,对列解锁 我们看DB2对于锁管理的开销还是比较的大,锁越多表明,这个操作花的时间就越长,开销就比较大. 那么Oracle是怎么来做的呢?咱们来看一下: 当我想要加锁的时候 1.找到要锁定的一行. 2.定位那一样,然后加锁 对,没错就是这么的简单.让你看到Oracle的实现就是这么的piece of cake!!Oracle不需要传统的锁管理器,事务只是找数据如果数据没有被加锁,则加锁. 那么Oracle没有了锁管理器,看似简单的问题,他是怎么实现的呢? 这 就要从数据块说起,在Oracle中,其最小的逻辑单元就是block,在每一个block头部,都保留有一个ITL的事务列表.每当一个事务要修改 block中所保留的行的时候,就会在在ITL的SLOT中记录一项.而每一行的行首还有一个Lock byte用来表示行的锁定,因此未commit的事务用ITL的slot和lock byte来表示那些被封锁的行. 刚才说过,Oracle的行 级锁是TX,是事务级的.如果一个事务要修改被另一个事务更新还没有提交的数据时,他就会阻塞.等待锁的释放,但是等待的绝对不是行的锁,而是事务锁 (TX)的释放.所以真正的TX锁释放了(而不是隐式的那些行).被阻塞的事务才可以继续进行.所以即使你加了savepoint也无用,回滚到某一个 savepoint只能释放某些隐式行上的锁,但是不能释放真正的事务锁. 那么ITL中的SLOT的数量是由谁决定的呢?其实一个slot项一般会占用block的24个字节,在建对象的时候会通过指定initrans和 maxtrans来设置slot的数目.需要注意的是Oracle 10g中这个maxtrans的设置已经被废弃,意思是说,即使我们指定了maxtrans,Oracle也会忽略这个限制,只要block有空 间,Oracle就会不受约束的扩大ITL中的slot. 2.TM(table level lock) 表级锁,其实就是向表加 锁了(废话嘛).那么在对一个表加锁之前,数据库需要做一些判断,首先是他要对表加的这个锁是否与表中所加的这个锁相容.其次,还要检查该锁是否与表中的 每一行上的锁相容,对于这一点如果我一个表里面有很多的行,那么如果我要对一个表加锁的话,就需要遍历表中的所有行,来查看锁的相容性,这对数据库来讲无 疑是高性能的一个障碍.所以呢,Oracle引出了一个意向锁的概念. 那么什么是意向锁呢?如果我给了一个节点加了一个意向锁,就表示我要对其下 层节点加一个同等类型的锁,意思也就是说要对一个节点加锁,就要先在其上层节点上加个意向锁,这样一来,如果我要对一个表加锁的话,那么只要判断和意向锁 的相容性就好了,不需要再遍历表中的行来检查每一行的锁了,这样系统的效率就大大提高了. 意向锁有那些类型呢? 1.Intent share lock(意向共享锁 IS):如果要对一个对象加S锁,那么首先就要在其上层节点加IS锁 2.Intent exclusive lock(意向排他锁 IX):如果要对一个对象加X锁,首先也要对其上级节点加IX锁. 3.Shared intent exclusive lock(共享意向排他锁):如果一个事务对某个表加了SIX锁的话,则表示整个事务要读取整个的表,同时又会更新个别行. 这样我们可以总结一下,在对数据库对象加锁的时候就有5种 X , S , IX , IS ,  SIX 因此Oracle的DML锁,在行级只有X锁,在TM级有5种就是我们刚刚提到的:X , S , IX , IS , SIX 表示起来就是,S , X , RS , RX , SRX 我 们可以看到,通常的DML操作(SELECT…FOR UPDATE、INSERT、UPDATE、DELETE),在表级获得的只是意向锁(RS或RX),其真正的封锁粒度还是在行级;另外,Oracle数 据库的一个显著特点是,在缺省情况下,单纯地读数据(SELECT)并不加锁,Oracle通过回滚段(Rollback segment)来保证用户不读“脏”数据。这些都极大地提高了系统的并发程度。(撤消对读取的块所做的块修改)由于意向锁及数据行上锁标志位的引入,极 大地减小了Oracle维护行级锁的开销,这些技术的应用使Oracle能够高效地处理高度并发的事务请求。 最后,给出两个表格是IT PUBer的朋友提供的:

T2

T1

Comments