locks
oracle通过latch保护短暂或间歇访问的数据结构.但latch不适用于保护较长时间访问的资源,比如database tables.locks允许多个会话加入到一个队列中,如果所访问的资源暂时不可用.
这样就避免了spinning.locks也允许多个会话共享资源,前提是它们的活动是相互包容的.
lock usage
oracle根据不同的目的或用途,分为不同的lock。下面介绍几类便于大家调优的locks.
transaction locks and row-level locks
oracle自我标榜的row-level locks实现机制是很微妙的。当一个事务修改一行记录时,会在对应数据块的块头的itl记录一条记录(或entry),并且每个row header(行头,就是记录头)
被修改指向itl的记录。
一旦发生变改,没有lock时。未提交事务的itl记录和所引用它的行头,会对所修改的行构建一个隐式的lock.
当另一个事务也想修改以上相同的行(记录)时,发现有一个未提交的事务修改了这个行,于是这个事务就会发生等待,不是等待row-level lock,而是在等待阻塞事务所产生的事务锁(记得:这个事务锁是以上未提交事务所产生的)。
当阻塞事务提交或rollback,它的事务锁将会release。因此它产生的隐式row-level locks也就release了,这样被阻塞的事务也可以继续进行了。注意:如果rollback到某个savepoint时,不会free先前被阻塞事务(这个事务等待一个行级锁).
buffer locks
row-level locks保护最低级可行粒度(级别)的数据完整性,会在一个事务期间强制保持它。但是,oracle在访问或修改cache中的一些blocks,也需要持有短暂的块级lock.使用buffer locks实现database buffer cache中blocks提供一种简单的读写的锁定.
虽然它们很少被提及并经常被授予,但它们对于数据完整性很重要,它在某些性能调优情形下很重要.
data dictionary locks
data dictionary中的数据对象的定义,在引用时,也要保护.在使用这些数据对象的定义时,有必要防止这些对象被删除,它们的对象定义信息被改变。当所依赖的sql被解析或执行时,
dictionary locks必须持有,在依赖的事务期间必须持有.
多种不同类型的locks用于dictionary locking.data dictionary rows用row cache enqueue locks来锁定它.所依赖的sql用library cache pins保护它(也就是lock it),
对应或依赖的事务持有dml locks(data maninpulation language)。从逻辑上讲,dml locks和library cache pins从属于或依赖于它对应的row cache enqueue locks.
但是这种依赖性是隐式的,用户看不到,但从结构方面是显式的.( 这里依赖比较复杂,多看几次,理下思路).
lock modes
locks用于复合和简单的对象。复合对象的典型例子和组成部分是一个表和它的记录。一个cache buffer就是一个简单的例子.
简单对象可能采用下列的模式锁定:
exclusive
一个会话要修改一个简单对象,在所访问的资源需要一个排它锁(exclusive lock)防止任何并发的访问.
shared
如果一个会话需要检查一个简单对象时,在所访问的资源上加上shared lock,有效确信数据结构不会被其它会话修改,此时是允许并发的共享访问的.
null
如果一个会话在缓存中保存了一个对象的信息.这时会以占位符的方式持有null mode lock,甚至这个资源并没有积极被使用。a null mode lock不禁止任何并发的访问,但如果这些资源
无效了,null mode lock对于这个会话起到一个触发器,通知这个会话的private cached information无效。记得:持有一个null mode lock和完全不持有一个lock的具有重要的区别.
对于复合的对象持有锁有如下模式:
sub-shared
如果一个会话需要以shared 模式访问一个复合对象的部分,如果此时对整个复合对象加一个共享锁,这样会产生过度的限制作用,因为它阻止exclusive模式访问复合对象的其它部分。这种情况下,采用sub-shared lock就合适.
sub-exclusive
如果一个会话需要exclusive模式访问复合对象的部分,此时sub-exclusive lock会有效起到作用
shared-sub-exclusive
当一个会话需要exclusive 模式访问复合对象的部分同时需要以共享模式访问整个复合资源,采用shared-sub-exclusive最好
以上lock modes适用于本地锁和ops实例的实例锁instance locks.
local lock modes instance lock modes
name symbol number name symbol number
no lock nlck 0
null n 1 null nl 0
sub-shared ss 2 concurrent read cr 1
sub-exclusive sx 3 concurrent write cw 2
shared s 4 protected read pr 3
shared-sub-exclusive ssx 5 protected write pw 4
exclusive x 6 exclusive ex 5
euqueue locks
oracle一些locks叫作euqueue locks.把对一个lock的请求放入一个队列,就是把这些请求放入它请求资源的阵列中.当引用或查阅一个特有的enqueue resource,比如cf(controfile)enqueue时,就是一个名词.
oracle使用两类local locks---一类用于lock和resource data structures在共享池中分配,另一类用于固定的队列及资源数据结构.
euqueue resources
入队资源的固定队列(数组)通过enqueue_resources来定义它的大小.队列中的slots数量会随时时间而变,查看v$resource就可以了.v$resource的每条记录代表每个资源,这个资源当时被一或多个会话以任何模式锁定。
因为一旦对这些资源的锁定release了,因此这些资源不会持续性的存在.
v$resource每条记录通过一个两个字符(表示资源类型)来标识这个资源,这两个数字编号的列可用于资源记录进行编码或者对通过其资源上面的锁保护的活动,这一切依赖于资源类型。比如,tx类型的资源,表示rollback segment的事务表transaction table
的记录。第一个标识的最高排序2 bytes包含rollback segment的编号,最低排序的2 bytes包含事务表的slot编号,但第二个标识包含rollback segment wrap或序列号.
所有入队操作访问入队资源结构(通过一个hash table).hash table是基于资源类型和编号标识。enqueue hash table的长度是用_enqueue_hash来设定。这个参数的默认值源于processes参数:
45 + 2*(processes+processes/10)
因为_enqueue_hash是直接源于processes而非enqueue_resources,如果enqueue_resources远远大于默认值,显式配置_enqueue_hash很有必要。否则会产生过长的enqueue hash chains。对于所有的hash tables,如果要调节buckets的数目,最好配置为质数.
访问enqueue hash chains是在enqueue hash chains latches保护情况下进行。child enqueue hash chains latches的数量,通过_enqueue_hash_chain_latches来设置,默认为cpu_count.在一个高并发的环境下,如果由于访问hash chains变得过度大,会产生对于enqueue hash chains latches的sleeps.但是对于这些latches的sleeps正常应该是竞争高级latch的次级结果,而不是源于
过长的hash chains.
hash tables and prime numbers
oracle在内部使用hash tables便于有效定位或查找对象.比如,用它查找或定位buffer cache的database blocks,用另一个hash table定位library cache的指定对象.
通过hash table定位一个对象,oracle采用一个算法转换对象名字或标识为一个编号。这个编号可能远远大于hash table的大小,通过取模function建立index和hash table的对应关系
多个对象可能同时映射到hash table entry.这叫作一个hash 冲突。oracle通常用冲突chains来处理它。这意味着发生冲突的对象通过一系列的指针把这些对象链接起来。这些对象被分配到相同的hash bucket.
基于hash访问的性能与hash chains的长度有很大关系,因为它们必须以线性被访问.因此hash tables必须非常大,以此确信平均hash chain的长度要适度.
如果以不均匀方式分配对象到hash buckets,可能会产生太长的hash chains.如果被hash的对象名字的模式用hash function不能乾地随机化处理.产生这种情况很正常吧.
设置hash buckets的数量为质数,你就能极大减少导致hash collisions的hash values模式的可能性(适用于取模function).
enqueue locking
除了enqueue resources,第二个固定的队列用于排队锁定--也就是说,enqueue locks保护它们本身。enqueue locks固定队列的大小,通过_enqueue_locks来设置,查询v$enqueue_lock来查看活动的记录数.
每个会话等待或持有一个资源的锁时,会使用一个enqueue lock structure.如果一或多个会话等待这个资源的locks时,它们的enqueue lock structures会通过一个双向链接列表,放在一起,以及enqueue resource structure(以列表头).会根据对locks维护和服务的次序来实现链表。比如,
以共享模式持有一个lock,第一个等待者需要以排它模式访问这个资源,此时其它会话(需要以共享模式访问资源)必须入队(对于所要请求的资源),而不管它们的请求是否与目前被锁定的资源(锁)的模式是否匹配.
同样的,双向链接列表用于连接enqueue lock structures(用于会话持有一个资源的锁)和(会话等待改变持有锁的模式)
改变一个锁的模式操作叫作:入队转变。比如,一个事务以sub-share mode对一个表持有一个lock,需要更新一个表的记录,此时enqueue lock必须转变为sub-exclusive mode.但是目前资源以不兼容模式(锁)被另一个会话持有,此时这个转变不能马上继续进行下去,enqueue lock structure被放在convertion queue中。
在新的入队请求之前,入队转换须以次序进行.
在入队操作期间,对于入队资源和入队锁固定自由列表(enqueue locks fixed array free lists)的修改,是在enqueue latch的保护下进行.这是一个enqueue latch。它们经常持有或release两次(在单一的入队操作期间)。但是,相关的enqueue hash chains latch会在这个入队操作期间持有.
enqueue waits
只要入队请求或入队转变不能及时或马上被授予(响应),会产生enqueue waits.因为另一个会话以不兼容模式持有锁.这个被阻塞进程记录一个入队等待enqueue wait.
wait parameters(enqueue waits)
参数 描述
p1 高次序2 bytes包含资源类型的ascii 编码.低次序2 bytes包含请求锁的模式
p2 资源的id1标识
p3 资源的id2标识
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/9240380/viewspace-660566/
,如需转载,请注明出处,否则将追究法律责任。