oracle 闩锁介绍

  oracle通过闩锁(latch)和锁定(lock)来实现资源的串行化。闩锁和锁定相同点是:都是用于实现保护数据的完整与准确性。不同点是:闩锁是 一个低级别,轻量级的锁,获得和释放的速度非常快。而锁定则持续的时间较长,通过队列,按照先进先出的方式实现。可以这么说:闩锁是微观领域的,锁定则是 宏观领域的。

      那闩锁到底起的是什么作用?这么说吧,只要涉及到内存地址的读和写,都需要通过获得闩锁(latch)来实现串行化。一次只能有一个服务器进程读或者写内存地址,这样就保证了存放在该内存地址数据的准确性。

      一个会话请求闩锁的时候,有可能这个闩锁正被其他会话占用。这个时候是否选择等待取决于你以什么模式请求闩锁,如果选择willing to wait(愿意等待),我们的会话就会睡眠一段时间继续请求。如果选择immediate(立即),我们的会话就会做其他的事情(比如获取另外一个相当的 空闲闩),而不是等待这个闩直到可用。

      由于一个闩可能有很多会话在等待其变得可用,这些等待者是否会排队呢,比如先等的排在前面?其实这个不会,这些等待者是在不断重复请求这个闩锁的,一旦这个闩锁被释放,最先请求的就会先得到。

     那这些等待者是如何进行等待的呢?其实等待闩锁是一个开销比较大的事情,如果闩锁不可用,我们就得等待。在一台多cpu的机器上(如果单cpu,就没有等待闩锁这一说了),我们的会话就会自旋(spin)。

      什么叫做自旋?就是我们的会话不切出cpu,会一直呆在cpu上,不断循环请求得到这个闩。因为切出cpu,醒来之后又要调入cpu非常浪费时间,而且这 个闩的持有者非常有可能正在另外一个cpu上忙于处理,而且会很快释放这个闩。大多数情况,我们的会话会很快得到这个闩的。如果请求很多次之后,还是不能 得到这个闩,我们的会话就会进行睡眠,让出cpu。

      由此可以看出,即使有的时候我们的cpu看起来很忙,其实没干多少事情。如果你的程序写得足够糟糕,那cpu大多数的时间在不断循环请求闩锁,其实没干多少实际的工作。这就是为什么写sql语句最好用绑定变量的方法。

      下面我们做一个测试:。我们会把一个编写得很好的程序和一个编写得不太好的程序进行比较,前者使用了绑定变量,而在编写得不好的程序中,每条语句使用了 SQL直接量或各不相同的SQL。为此,我们使用了一个很小的Java程序,它只是登录Oracle,关掉自动提交,并通过一个循环执行25 000条不同的INSERT语句。

 

     要评估这些程序以及它们在多用户环境中的行为,我们用Statspack来收集度量信息(什么是statspack参考我的这篇博文:http://liwenshui322.iteye.com/admin/blogs/1183027),

     如下:
(1) 执行一个Statspack快照来收集系统的当前状态。
(2) 运行程序的N个副本,每个程序向其自己的数据库表中插入(INSERT),以避免所有程序都试图向一个表中插入而产生的竞争。
(3) 在最后一个程序副本执行后,紧接着取另一个快照。
然后只需打印出Statspack报告,并查看完成N个程序副本需要多长时间,使用了多少CPU时间,主要的等待事件是什么,等等。

 

    使用绑定变量java源码:

package cn.netjava.latch; import java.sql.Connection; import java.sql.PreparedStatement; public class LatchTestMain { public static void main(String args[]) throws Exception{ Connection conn = ConnectOracle.getConn(); conn.setAutoCommit(false); String sql = "insert into latch_test1(id) values(?)"; PreparedStatement ps = conn.prepareStatement(sql); for(int i=0;i<25000;i++){ ps.setInt(1, i); ps.executeUpdate(); } conn.commit(); conn.close(); } }

 

 

不使用了绑定变量的java源码

package cn.netjava.latch; import java.sql.Connection; import java.sql.Statement; public class LatchTestMain { public static void main(String args[]) throws Exception{ Connection conn = ConnectOracle.getConn(); conn.setAutoCommit(false); Statement st = conn.createStatement(); for(int i=0;i<25000;i++){ String sql = "insert into latch_test1(id) values("+i+")"; st.execute(sql); } conn.commit(); conn.close(); } }

 

 

  

 

 

 

 

  不使用绑定变量与使用了绑定变量Statspack报告对比

 

   不使用绑定变量:

 使用绑定变量:



 

        对比可以看出1S硬解析的次数不是一个数量级的。

 

    不使用绑定变量

   

 
    使用绑定变量



 

   对比可以看出cpu的时间也有很大区别。说明如果不使用绑定变量,大部分时间都会耗在硬解析这项重复没有意义的事情上面。

 

   上面的报告都是单用户模式下(一个用户)。在实际情况当中,肯定是多用户模式了,假如我们一次跑4个程序副本看看报告是什么样子。

   不使用绑定变量

 

 

 

    使用绑定变量

 

 

 

   发现不使用绑定变量的话,随着用户的增加,硬解析次数也增加了。而使用了绑定变量的话,硬解析次数没有什么改变。在这里是0,因为我们以前跑过一次了。

 

  不使用绑定变量

 


 
 使用绑定变量

 


 
 对比单用户模式,不使用绑定变量的话,cpu耗时4用户是单用户的4倍多(理论上应该是4倍,至于多出来的时间,应该是耗在闩自旋上面了。)使用了绑定变量只有3倍。

   以共享池为例,我们来看闩自旋。

   单用户模式不使用绑定变量

  

  

   4用户模式不使用绑定变量

 


 

   很明显,对于shared pool 请求的次数后者是前者的4倍左右,但是Misses次数(请求闩锁失败)要高出好多,屡次请求不到而进入睡眠的也高出好多。由此可以看出,如果不使用绑定 变量的话,在数以百计的用户同时访问的时候,简直是自寻死路。 同时访问的用户越多,闩自旋的概率越大,浪费cpu的时间就越多。
 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/23141985/viewspace-716837/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/23141985/viewspace-716837/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值