Oracle本身是一个多用户并发处理系统,在同一个时间点上,可能会有多个用户同时操作数据库,这就涉及两个重要的问题1、这些用户之间的操作不会互相破坏,比如两个用户同时在相同的物理位置上写数据时,不能发生互相覆盖的情况,这叫做串行化,也就是说,即便两个用户同时在写,也必须有先后,一个用户写完,另一个用户继续写,串行化会降低系统的并发性,但这对保护数据结构不被破坏来说则是必须的2、在满足串行化的前提下,如何将并发性提升到最大Oracle中通过使用闩锁(latch)和锁定(lock)Latch和lock都是实现串行化的方法latch是一个低级别的,轻量级的锁,获得和释放的速度都很快lock可能持续很长时间,通过使用队列,先进先出的方式实现锁的白话意义:一种资源,如果可能发生多个进程同时访问的情况,造成资源的破坏,那么就需要给这种资源上一个锁,如果这种资源很简单,例如就是内存的分配和释放,那么就使用latch,如果这种资源相对复杂,有一定的逻辑判断,那么就需要使用lock资源的意义很广泛,因为进程总是通过内存来做修改、读取,因此资源都分布在内存中。闩锁的概述(latch)Oracle使用闩锁来实现内存的分配和释放例如某个用户进程A发出一条update语句,要去更新58号数据块里的某条记录,则该用户进程对应的服务器进程在写内存的时候,到58号数据块,并往里写内容,A在写58号数据块的过程中,这时另外一个用户进程B发出insert语句,要将某个新的记录插入到58号数据块中,如果没有一定的保护机制,A正要写入的空间可能被B抢先写入,B要写入的空间可能被A抢先写入,不管哪个用户先抢先写入,造成的结果就是,58号数据块的数据都混乱了如果使用latch来进行保护,简单的描述,任何进程要写数据块时,都必须先获得latch,在写入过程中,一直持有latch,写完以后,释放latch当A在写入58号数据块的时候,先获得latch,B也要写58号数据块,这时B尝试获得latch,发现该latc
h被A持有,B进入等待状态,直到A释放latch,B获得latch以后,才能在58号数据块中写入数据不只是写数据块需要使用latch,shared pool中就没有数据块。凡是涉及内存的读和写,就需要通过获得latch来实现,一次只能有一个服务器进程在读或写内存。Oracle在实例管理中,不管是buffer cache、shared pool还是log buffer,都引入了各种各样的latch。可以这样来?斫鈒atch,通过某个变量值的变化来实现,变量值为0则说明latch没有被其它进程获取,变量值为非0则说明latch被其他进程获取Latch是以微妙来计算的(百万分之一秒),操作非常快凡是涉及内存里的某个地址读写的,都要涉及到latch所谓轻量级锁,就是实现非常的简单,起的作用也是非常的初级。Latch 分为两种类型1、愿意等待(willing – to - wait)大部分的latch都属于这种这种类型的latch都是通过test-and-set的方式获得的,也就是说,如果当前进程不能获得latch的时候,会绕着CPU旋转,而不放弃CPU,这就是所谓的SPINCPU实际上就是执行一段空循环,通过执行空循环,一只占用着CPU1、进程没有获得latch,为什么还要占用着CPU呢?因为latch本身是一个很快速的动作,因此可能等一会就能够获得latch,进程一旦获得CPU,但是没有获得latch,如果放弃CPU,那么需要进行上下文的切换,下次再次尝试获得latch时,又要进行上下文切换,可能消耗更多的时间,因此进程不能获得CPU的时候,会通过执行一段空代码绕着CPU转,然后再次尝试获得latch。2、如果仍然不能够获得,继续旋转,当反复旋转CPU并尝试获得latch的次数超过某个上限时(该上限由隐藏参数控制),这时进程会释放CPU,并进入sleep状态,进程一旦进入sleep状态,就会抛出一个等待事件,并记录在vsession_wait里,进程正在等待latch的信息会出现
在这个视图中3、一个进程会睡眠0.01秒,然后醒来,并再次尝试获得latch,如果旋转CPU的次数达到上限值,仍然不能获得latch,则再次进入睡眠,这时会睡眠两倍的时间,以此类推,直到达到睡眠的最大值:0.2秒上面的情况是数据库服务器具有多个CPU的情况,如果只有一个CPU,就不存在旋转CPU的情况,一旦获得不了latch,就进入睡眠不等待(no-wait)这种类型的latch较少,对于这种类型的latch来说,都会有很多个可用的latch当一个进程请求其中的一个latch时,会以no-wait模式开始请求,如果所请求的latch不可用,则进程不会等待,而是立即请求另外一个latch,只有当所有的latch都不能获得的时候,才会进入等待如果latc被争用,通常都表现为CPU资源使用过高,如果CPU资源很紧张,利用率总是在90以上,甚至总是在100,主要原因如下1、SQL语句没有使用绑定变量,如果没有使用绑定变量,或者书写SQL时随意性过大,比如大小写混用、则Oracle对每一条SQL语句都要进行解析,也就是非常频繁地读写shared pool里的内存块,从而导致与解析SQL相关的latch争用2、执行sql语句时,扫描的数据块过多,或者说SQL语句写的比较低效,导致扫描很多的数据块才能返回所要的记录。因为在查、扫描数据块的过程中,进程也要获得latch,直到到数据块为止。一旦发生latc争用,就会导致CPU繁忙假设进程A执行一条SQL语句需要访问10000个数据块,那么该进程在扫描数据块的过程中,一直持有latch,而另一个进程B也要执行SQL语句,但是A持有了latch,导致B 无法获得,于是旋转一会CPU,再去获得latch,直到睡眠才释放CPU,接下来C进程也要执行SQL,同样的,由于A持有了latch,导致C无法获得,于是旋转一会CPU,再去获得latch,直到进入睡眠才释放CPU,如果类似进程很多的话,CPU总是在旋转,也就是在做空的循环,而无法做其他的事情,因此体现出C
PU使用率过高因此:要解决latch争用,关键在于共享SQL语句(比如绑定变量、规范SQL语句的书写),优化SQL语句,使其搜索以及扫描的数据块的个数降到最低锁定lock Lock用来控制多个用户对表里相同数据的并行访问时间用户操作用户操作9:00 A Update t set c110 where id1 and c15 9:01 B Update t set c120 where id1 and c15 9:02 A Commit 9:03 B Commit 9:04 A Select c1 from t where id1如果没有使用锁定来管理事务,则在9:04的时候,用户A检索id1的c1列值时,显示为20,用户A的修改被B覆盖了时间用户操作用户操作9:00 A Update t set c110 where id1 and c15
锁定id为1的记录。9:01 B Update t set c120 where id1 and c15 由于该记录被A用户锁定,因此该命令执行时发生等待。9:02 A Commit 提交以后释放锁定。9:03 B 由于A释放了锁定,因此9:01时发出的update语句可以继续执行下去。由于这时c1已经不等于5,而是10,因此该update语句没有更新到记录。9:04 A Select c1 from t where id1 使用锁定以后的情况。在锁定中,存在下面的两种基本情况1、排他锁(X 锁),一旦用户对某个资源添加了排他锁,则其他用户都不能再对该资源添加任何类型的锁,直到该用户释放了资源上的X锁2、共享锁(S锁),一旦用户对某个资源添加了共享?  蚱渌 没Ф疾荒茉诟米试瓷咸砑覺锁,只能添加S锁,直到该用户释放了S锁为止DML事务锁定机制能够保证当某个用户正在更新表里的一行数据时,其他用户不能同时更新相同的数据行,而且也不能删除或修改被更新的表行级锁(TX锁)update employee set last_name‘xkj’ where exployee_id1001、Oracle对该SQL语句进行解析,到exployee_id为100的记录所在的数据块(假设为58号数据块),并到一个可用的undo数据块,将last_name列上被更新前的旧值放入该undo
数据块2、在58号数据块的头部分配一个ITL槽,在该槽里存放当前的是事务ID、SCN 号、所使用的undo数据块的地址,以及未提交的标记等信息3、在58号数据块中,到被更新的数据行,在数据行头部设置一个锁定标记,并在头部记录当前事务所使用的ITL槽号,做完这些工作4、控制权交给用户,该锁定说明当前用户在被修改的数据行上已经添加了X锁如果这时,另一个用户B也对exployee_id为100的记录进行修改,则其过程和上面描述一样,只不过B在对数据行的头部设置锁定标记的时候,发现该数据行头部已经有一个锁定标记了,说明该记录已经添加了X锁,于是用户B 必须等待,等待X锁被释放。锁定一条记录,并不影响其他用户对该记录的读取,例如如果用户发出一条SQL语句,检索exployee_id为100的记录信息,这时服务器进程发现被检索的记录有锁定标记,说明该记录已经被其他用户修改了,但是还没有提交。于是根据数据行头部记录到ITL槽的号码,在数据块头部到ITL槽,并根据其中记录的undo数据块的地址,到该undo数据块,将其中所保存的改变前的旧值取出来,并构建CR(consistent read 读一致性)块,根据CR块的内容,将用户所需要的信息进行返回。对于Oracle来说,行级锁只有X锁定模式,没有S锁定模式,更新数据行,只是锁定被更新的数据行表级锁用户A已经发出了更新exployee_id为100的记录的SQL语句,当A还没有提交之前,另外一个用户D发出下面的语句drop table employee由于用户A还没有提交所做的事务,该事务还没有结束,其他用户不能删除该表,否则A所发出的事务就无法正常结束,为了阻止用户D的删除操作,我们能够想到的最直观的方法是在执行删除表的命令以前,先依次检查exployee表里的每一条记录,查看每一条数据行的头部是否存在锁定标记,如果是,则说明正有当前事务在更新表,删除表的操作必须等待显然这样存在很大的性能问题实际
上,当我们在对employee表的数据进行更新时,不仅会在数据行的头部记录行级锁,而且还会在表的级别上添加一个表级锁,这样可以提高锁管理的性能表级锁共有5种模式1、行级排他锁(Row exclusive)RX锁当我们进行DML时,会自动在被更新的表上添加RX锁,可以执行LOCK命令显式的在表上添加RX锁允许其他事务通过DML语句修改相同表里的其他数据行允许使用lock命令对表添加RX锁定不允许其他事务
对表添加X锁B事务,显然不允许添加X锁。A事务A事务允许B事务使用lock添加一个行级排他锁如何结束锁定,使用rollback行级共享锁(row shared RS锁)在表上添加了一个行级的共享锁,这里面的select可以是多条记录,往往是多条记录。用户在执行select的时候,不希望其他用户对这些记录进行更新,经常发出这些命令。查询完成以后,发出rollback命令解锁表上添加了RS锁以后,不允许其他事务对相同的表添加X锁,但是允许其他事务通过DML对表里面的其他数据进行修改,也允许添加行级排他锁不允许对锁定的数据进行修改。事务A 事务B 允许对没有锁定的数据进行修改事务B 在对表进行DML的时候,已经在表上添加了行级排他锁,因此在有行级共享锁的表上可以添加行级排他锁手工的可以添加行级排他锁,和上面的效果一样。不允许添加排他锁共享锁(shared)S锁不允许任何用户更新表,但是可以添加行级共享锁RS 不允许进行DML操作允许进行RS共享锁和排他锁的区别是可以允许RS排他锁(exclusive )X锁其他事务不能对表进行任何的DML和DDL操作,只能进行查询。共享行级排他锁(shared row exclusive)SRX锁不能对相同的表进行DML操作,也不能添加共享锁S X RS RX SRX N/A S √ × √ × × √ X × × × × × √ RS √ × √ √ √ √ RX × × √ √ × √ SRX × × √ × × √ N/A √ √ √ √ √ √锁之间
的兼容性,有了这个锁,能不能有另外一个锁。一块操