ITPub博客

首页 > 数据库 > Oracle > 资源供给:并发性控制和mutex之一

资源供给:并发性控制和mutex之一

原创 Oracle 作者:sunsapollos 时间:2013-12-14 00:27:13 0 删除 编辑
简单案例描述: 某商业银行业务系统表现出在高峰期CPU消耗很高,有些消耗CPU特别高的进程,但总是会变化,业务系统响应还基本可以接受。在CPU Time表现中Parse CPU相对比较高,Hard Parse不高,系统偶尔出现cursor pin: S,v$mutex_sleep_history表现出较高的gets和sleeps。经过综合判断为mutex的机制冲突引起,应用patch: 6904068之后CPU消耗快速降低,当然性能是不会增加的,只是释放了CPU资源。

     mutex的实现,是Oracle性能优化者的幸运,也是性能优化者的不幸。幸运在于除了Oracle bug之外,mutex很少会出现问题。不幸当然也在于此,当出现问题的时候,往往只能去查询是否bug,很可悲呀。

     library cache pin 和cursor pin with mutex。
    Oracle在11g之前是主要把pin cursor相关的library cache pin转换成了mutex,所以我们在这里也主要讲pin cursor。
    从性能优化的角度出发,library cache pin和cursor pin with mutex两者没有很大区别,mutex比较library cache pin提供了更加清晰的视角。
  
      library cache pin的实现应该不同于普通的latch,采用某种类似于队列的形式实现。library cache pin不同于其他的latch,他会针对每个cursor创建pin,也就是可能几十万甚至几百万的pin,显然采用普通latch实现成本太高。我们不 管他如何实现,只要知道其基于某种队列就可以了。cursor mutex相对比较library cache pin要高级,他采用shared latch的类似应用计数实现,也就是 CAS原子操作。
    pin cursor在什么时候发生?   
  pin cursor for create cursor
  pin cursor for execute cursor   
   可能还会有其他场景会发生pin cursor,但应该主要就是基于上面两种情况。

  为什么需要pin,pin的主要目的是为了防止被交换出内存,同时提供并行访问控制。

   我们来看看:
   Pin cursor for Execute Cursor:
       这个时候,我们准备执行该SQL语句(Cursor),需要把Cursor Pin(Shared)在Buffer中(child cursor),在Pin Buffer的过程中,我们需要完成以下操作:
(1)、绑定变量填充
(2)、cursor依赖对象Pin以防止被(Shared)

  显然Pin cursor可能的冲突主要来自于以下两个方面:
  (1)、依赖的object被交换出内存,导致pin的成本很高
  (2)、依赖的对象被ddl操作以至于无法获得PIN
   我一直不明白Oracle为什么允许在Parse过程中的对象被允许交换到内存中,Parse之后按照道理是需要马上执行引用,不应该被牺牲掉。
 
     在相对内存充足的系统中,如果不发生手工清理的flush pool,一般很少会发生以来的object被交换,因为我们刚刚在parse过程中把所依赖的对象都装载进来。至于ddl操作则需要在依赖对象上获得 Exclusive Lock and Exclusive PIN,并且导致依赖的cursor无效。从理论上讲,cursor pin的进程在被ddl中断之后应该重新执行parse过程,但在实践中的发现基本表现为等待library cache pin的进程永久等待,不会进行释放。
    从cursor pin的角度而言,我们只要做到避免在高峰期执行ddl以及相对充足的shared pool,一般来说可以避免library cache pin或者mutex cursor冲突。

    mutex:
    cursor: pin s wait on x
     cursor: pin s      
    cursor: pin x

   以上三个冲突主要在pin cursor的阶段。
   cursor: pin s wait on x为正常的cursor执行pin,一般为所依赖的对象不再内存中导致成本很高导致,等待pin依赖对象。
              当然ddl操作也是cursor: pin s wait on x的主要原因。
   cursor: pin s为正常的执行,在极高并发的时候会发生,主要原因在于mutex采用CAS机制,在引用计数变更的时候不允许其他session pin cursor,这个时候的等待表示为cursor: pin s。对于cursor: pin s如果不是Oracle bug的话,一般只能通过应用程序层面来解决,避免cursor热点,这个和以前处理高并发的library cache pin是一致的。
             事实上,大家可以发现相当多的cursor: pin s发生在select * from dual之类的语句上,很多应用对于dual的引用极为频繁,从而导致其产生pin cursor冲突。一般的处理方式为改写语句:比如select * from dual为cursor pin最严重的语句,则改写为以下方式:
             select * from dual D1;
             select * from dual D2;
             等等,使其成为不同的cursor,自然就不会出现在cursor: pin s层面上的冲突了。
     cursor: pin x,这个层面应该很少见,一般只有在cursor在pin过程中被交换到出内存,需要从内存中再次加载回来才会出现。当然某些需要对于cursor进行清 理的操作也需要获得cursor: pin x,比如flush shared pool,pugre cursor等等。

     绑定变量的填充发生在另一个层面上,一般为cursor: mutex x,一般很少会发生在绑定变量层面的冲突。
     cursor: mutex x
     cursor: mutex s

     应该极少会看到这个层面的冲突。
     如果有冲突发生,主要在两个层面可能发生:
     hard parse在生成cursor和children cursor的时候需要cursor: mutex x,虽然大量的文章认为这个时候会在依赖对象上获得exclusive lock and exclusive pin,但个人并不倾向于在hard parse的需要的在依赖对象施加exclusive pin,个人倾向于施加的是shared pin,除非是不再内存中。有兴趣的童鞋可以验证一下。
    hard parse仅仅在cursor被重用的时候才有可能会发生cursor: mutex x,所以个人认为hard parse和cursor: mutex x具有一定关系,但并不是绝对的。

     另一个可能会产生cursor: mutex x的场景应该是Create New children,也就是高版本场景。高版本需要不断的更新LCO的children table部分,也就是cursor部分,需要获得mutex x,大量高版本自然会引起响应的等待。
     cursor: mutex s 主要对于parent cursor进行引用查看的时候发生,什么时候会对parent cursor做exclusive,似乎只有age in and age out了。

     综合上面而言,对于mutex和library cache pin的优化措施事实上是很简单的:
    (1)、足够的shared pool
    (2)、控制DDL
    (3)、控制高版本
    (4)、对于高并发的SQL,从语句级别进行人工人点划分。
     当然,考虑Oracle bug也是一个最主要的思考方向。
    

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

请登录后发表评论 登录
全部评论
专注于Oracle,BI,Security,DR &^BCP,Performance tuning

注册时间:2013-10-15

  • 博文量
    68
  • 访问量
    725324