深入理解Oracle中的Mutex

 了解 Oracle Mutex

 

虽然Mutex中文翻译为互斥锁,但为了和OS mutex充分的区别,所以我们在本文里称Oracle Mutex为Mutex。

 

Oracle中的mutex,类似于Latch,是一种低级的串行机制,用以控制对SGA中部分共享数据结构的访问控制。  Oracle中的串行机制有不少,引入它们的目的是避免一个对象出现下述现象:

  • 当某些进程在访问该对象时,该资源被重新分配
  • 当某些进程在修改它时,被其他进程读取
  • 当某些进程在修改它时,被其他进程修改
  • 当某些进程在读取它时,被其他进程修改

 

不同于Latch,Mutex的使用更灵活,用途更多,例如:

  • 哪些需要被mutex保护的共享数据结构可以有自己独立的mutex,即一个对象拥有自己独立的mutex,不像Latch往往一个需要保护大量对象,举例来说,每一个父游标有其对应的mutex, 而每一个子游标也有其对应的mutex
  • 每一个数据结构可能有一个或多个mutex保护,每一个mutex负责保护其结构的不同部分
  • 当然一个mutex也可以用来保护多于一个的数据结构

 

理论上mutex即可以存放在其保护的结构本身中(其实是嵌入在结构里),也可以存放在其他地方。 一般情况下Mutex是在数据结构需要被保护时动态创建出来的。 如是嵌在需要保护结构体内的mutex,则当 所依附的数据结构被清理时 该mutex也将被摧毁。

 

 

Mutex带来的好处

虽然mutex和latch都是Oracle中的串行机制,但是mutex具有一些latch没有的好处

 

更轻量级且更快

Mutex作为Latch的替代品,具有更快速获得,更小等优势。 获取一个mutex进需要大约30~35个指令, 而Latch则需要150~200个指令。一个mutex结构的大小大约为16 bytes,而在10.2版本中一个latch需要112个bytes,在更早的版本中是200个bytes。 从200个bytes 精简到112个是通过减少不必要的统计指标 SLEEP1~SLEEP11、WAITERS_WOKEN, WAITS_HOLDING_LATCH等从而实现的。今后我们将看到更多关于Latch的代码优化。

 

减少伪争用

典型情况下一个Latch保护多个对象。 当一个Latch保护多个热对象时,并行地对这些对象的频繁访问让latch本身变成性能的串行点。 这也就是我们此处说的伪争用点, 因为争用是发生在这个串行保护的机制上,而不是进程去访问的对象本身。与latch不同, 使用mutex的情况下Oracle开发人员可以为每一个要保护的数据结构创建一个独立的mutex。 这意味着Latch的那种伪争用将大大减少,因为每一个对象均被自己独立拥有的mutex保护

 

 

 Mutex在一些地方替代了latch和PIN

 

一个Mutex可供多个Oracle进程并行地参考,反过来说进程们可以以S(Shared 共享) mode模式参考一个Mutex。以S mode一起共享参考这个mutex的进程的总数成为参考总数reference count。Mutex自身结构中存放了这个ref count的数据。另一方面,mutex也可以被以X (Exclusive)mode排他模式被仅有一个进程所持有Held。

 

Mutex有2种用途,一方面他们可以充当维护必要串行机制的结构,如同latch那样; 同时也可以充当pin,避免对象被age out。

 

举例来说,mutex结构中包含的ref count信息可以用作替代library cache pin。 在mutex充当cursor pin之前,当一个进程要执行=>pin一个cursor时需要做的是针对性地创建library cache pin和删除这个library cache pin(均为S mode)。mutex充当cursor pin之后,进程只需要增加和减少mutex上的ref count即可。

当某一个进程首次解析一个游标 Cursor,他将临时创建并移除一个library cache pin,但是该进程后续的解析或执行进要求增加或者减少ref count。注意在这个增加/减少ref count的过程中无需acquire latch,这是因为mutex自身能起到限制串行访问修改ref count的作用。 当一个进程要移除自己的mutex pin时,它减少ref count,同样的无需acquire 任何latch。

 

Mutex和Latch的交互

Latches和Mutex 是独立的串行机制, 举例来说一个进程可以同时持有latch和mutex。 在进程异常dead的情况下,一般latch要比Mutex更早被PMON清理。 一般情况下不存在mutex的死锁。 不像latch,在早期版本例如9i之前我们经常遇到latch死锁的问题。

 

Mutex的用途

在版本10.2中仅仅有 KKS 这个内核层是mutex的客户,KKS 意为 Kernel Kompile Shared, 它是Library Cache中的shared cursor游标共享部分层次的代码。 在之后的版本中,ORACLE开发部门更多地使用了Mutex,不局限于KKS。

 

KKS游标共享如何使用Mutex

kks 使用mutex以便保护对于下述基于parent cursor父游标和子游标child cursor的一系列操作。

 

对于父游标parent cursor的操作:

  • 基于发生的不同操作,对应不同的等待事件:
    • 在某个父游标名下创建一个新的游标                     ==> cursor:mutex X
    • 检查一个父游标                                                            ==> cursor:mutex S
    • 绑定值捕获                                                                    ==> cursor:mutex X
  • 保护父游标的mutex嵌入在父游标结构内
  •  针对父游标parent cursor的Mutex类型为’Cursor Parent’ (kgx_kks2).
  •   针对父游标parent cursor的Mutex等待事件均为’ Cursor: mutex *’的形式

 

针对游标统计信息的操作

  • 基于对不同的游标统计信息的操作有不同的等待事件:
    • 构造,更新游标相关的统计信息                                              ==> cursor:mutex X
    • 检测游标相关的统计信息,例如访问V$SQLSTATS            ==> cursor : mutex S
  • 相关的游标可能在父游标中,也可能在游标统计信息相关的hash table上
  • 针对游标统计信息的Mutex类型为Cursor Stat (kgx_kks1)
  •  针对游标统计信息的Mutex等待事件均为’ Cursor: mutex *’的形式

 

 Mutex是如何替代library cache pin来保护cursor heap的?

  • 传统的’library cache pin’在10.2.0.2之后默认被取代, 此处PIN被Mutex及其ref count取代。 当进程执行游标语句时或者需要PIN,或者需要hard parse一个子游标heap。
  • 在版本10.2.0.1中, 使用mutex部分代码替代PIN的功能默认是不激活的,实际上这取决于隐藏参数_KKS_USE_MUTEX_PIN,在10.2.0.2之后_KKS_USE_MUTEX_PIN默认为TRUE。 换而言之在版本10.2中我们还是可以关闭KKS使用MUTEX替代PIN保护CURSOR的, 但是在版本11g中则几乎无法关闭MUTEX。 注意10.2中仅当KKS真正使用MUTEX时,library cache pin不再用作cursor pin。
  • 基于对不同的游标统计信息的操作有不同的等待事件:
    • 为执行某个SQL而PIN一个游标Cursor                        ==>Cursor: Pin S Wait on X
    • 当执行一个游标而PIN Cursor,而该Cursor正被其他进程以S mode检测             ==>  cursor:pin S
  • 当试图重建一个游标Cursor  ==> Cursor: pin X  该等待事件一般不太会看到,因为当一个游标正被执行,且其需要重建时会有另一个游标被创建
  • 保护游标的mutex嵌入在游标结构内
  • Mutex类型为’Cursor Pin’ (kgx_kks3)
  • 等待事件均为 ‘cursor: pin *’的形式

 

 KKS使用MUTEX情况下SQL语句的 解析与执行的收益

 

在版本10.2中, 以下是几个SQL解析与执行从MUTEX哪里获得主要收益:

  • 在某个父游标下构建一个新的子游标
    • 首先这种构建新子游标的操作更廉价了,  当时Maclean仍要告诫你 一个父游标下过多的子游标仍不是一件好事情
  • 对父游标的检测
    •  在找到一个合适的游标并执行前,父游标需要被适当检测。 对父游标的这种检测目前也使用mutex来保护了,所以这种检测更的成本更低了
  • 对于已经加载在Library Cache 中的SQL语句重复执行
    • 常规情况下,当一个进程要执行SQL游标前总是必须要先pin它
    • 不使用MUTEX的情况:若游标处于OPEN状态下以便今后的重复执行,且参数cursor_space_for_time(CSFT  目前已不推荐使用该参数)为TRUE,则每一次重复执行可以不需要library cache pin。 若游标处于OPEN状态下但是cursor_space_for_time=false,则进程在重复执行SQL游标前总是要先拿library cache pin
    • 使用MUTEX的情况: 相反,若使用mutex来替代library cache pin时,则无需关心cursor_space_for_time 。 仅第一个进程需要做一个PIN,其他后续进程都只需要简单地在对应保护cursor heap的mutex上拿一个共享reference 。

 

查询SQL统计信息

通过V$SQLSTAT视图(本质上是X$KKSSQLSTAT)访问SQL统计信息时,其所需要的CPu和获取的Latch数量要远远少于访问其他V$SQL视图。 在早期版本中, 并行地访问V$SQL或者V$SQLAREA视图会造成 library cache latch的争用。

 

 

 

Mutex 的统计信息

下面是一个AWR中的Mutex Sleep Statistics, 这些数据主要来源于V$MUTEX_SLEEP视图。

 

Mutex Sleep Summary

  • ordered by number of sleeps desc
Mutex Type Location Sleeps Wait Time (ms)
Library Cache kglhdgh1 64 2,356 0
Library Cache kglpnal2 91 2,345 0
Cursor Pin kkslce [KKSCHLPIN2] 2,084 0
Library Cache kglpin1 4 956 0
Library Cache kglhdgn2 106 784 0
Library Cache kglpndl1 95 691 0
Library Cache kglpnal1 90 605 0
Library Cache kgllkdl1 85 580 0
Library Cache kgllkal1 80 404 0
Library Cache kglllal3 111 282 0
Library Cache kglllal1 109 218 0
Library Cache kglhdgn1 62 163 0
Library Cache kgllldl2 112 156 0
Library Cache kgllkc1 57 105 0
Library Cache kglget2 2 100 0
Library Cache kglini1 32 53 0
Library Cache kglget1 1 31 0
Cursor Pin kksLockDelete [KKSCHLPIN6] 22 0
Library Cache kgllkal3 82 18 0
Library Cache kglUnsetHandleReference 120 10 0
Cursor Pin kksxsccmp [KKSCHLPIN5] 10 0
Library Cache kglobld1 75 8 0
Cursor Pin kksfbc [KKSCHLPIN1] 8 0
Library Cache kglUpgradeLock 119 7 0
Library Cache kglhdgc1 102 2 0
Cursor Pin kksfbc [KKSCHLFSP2] 2 0
Library Cache kgldtin1 42 1 0
Library Cache kglhbh1 63 1 0
Library Cache kgllkal5 84 1 0
Library Cache kglrdtin1 44 1 0
Cursor Parent kkscsPruneChild [KKSPRTLOC35] 1 0

 

Mutex的类型Mutex Type

Mutex的类型其实就是 mutex对应的客户的名字,  在版本10.2中基本只有KKS使用Mutex,所以仅有3种:

  • Cursor Stat (kgx_kks1)
  • Cursor Parent (kgx_kks2)
  • Cursor Pin (kgx_kks3)

 

在版本11g中扩展了对Mutex的使用,在Library Cache的HASH BUCKET中嵌入了mutex以保护hash bucket,所以多了一种mutex type : Library Cache

 

 

哪些代码函数会申请Mutex?

 

 

Oracle中哪些代码函数会申请Mutex? 例如KKSFBC等,其实很像 V$LATCH_MISSES 的location列

10.2中最常见的下面的几个函数

kkspsc0  -负责解析游标 – 检测我们正在解析的游标是否有对象的parent cursor heap 0存在

kksfbc           –  负责找到合适的子游标 或者创建一个新的子游标

kksFindCursorstat  

 

11g开始有大量函数需要用到Mutex了

SQL> select location from X$MUTEX_SLEEP_HISTORY;

LOCATION
—————————————-
kkslce [KKSCHLPIN2]
kksfbc [KKSCHLFSP2]
kglhdgn2 106
kglpin1 4
kglhdgn2 106
kglllal1 109
kglpin1 4
kglpndl1 95
kglpin1 4
kglpin1 4
kksfbc [KKSCHLFSP2]
kglhdgn1 62
kglpnal1 90
kglllal3 111
kglpnal1 90
kglpnal1 90
kglget2 2
kglllal3 111
kglget2 2
kglobld1 75
kkslce [KKSCHLPIN2]
kglpndl1 95
kglpndl1 95
kglpin1 4
kkslce [KKSCHLPIN2]
kglpin1 4
kglget2 2
kglllal1 109
kgllkc1 57
kglget2 2
kglpnal1 90
kglpin1 4
kglpin1 4
kglpin1 4
kgllkdl1 85
kglllal3 111
kgllldl2 112
kglpin1 4
kglpndl1 95
kkslce [KKSCHLPIN2]
kksLockDelete [KKSCHLPIN6]
kglpndl1 95
kkslce [KKSCHLPIN2]
kglpnal1 90
kglpin1 4
kglpin1 4
kgllldl2 112
kgllkdl1 85
kglpin1 4
kglhdgn2 106
kglhdgn2 106
kksLockDelete [KKSCHLPIN6]
kglhdgn1 62

 

 

Mutex的Get和Sleep

当一个Mutex被申请时, 一般称为一个get request。 若初始的申请未能得到授权, 则该进程会因为此次申请而进入到255次SPIN中(_mutex_spin_count Mutex spin count),每次SPIN循环迭代过程中该进程都会去看看Mutex被释放了吗。

若该Mutex在SPIN之后仍未被释放,则该进程针对申请的mutex进入对应的mutex wait等待事件中。 实际进程的等待事件和等待方式由mutex的类型锁决定,例如 Cursor pin、Cursor Parent。  举例来说,这种等待可能是阻塞等待,也可以是sleep。

但是请注意在V$MUTEX_SLEEP_*视图上的sleep列意味着等待的次数。相关代码函数在开始进入等待时自加这个sleep字段。

等待计时从进程进入等待前开始计算等待时间, 当一个进程结束其等待,则等待的时间加入都总和total中。  该进程再次尝试申请之前的Mutex,若该Mutex仍不可用,则它再次进入spin/wait的循环。

 

V$MUTEX_SLEEP_HISTORY视图的GETS列仅在成功申请到一个Mutex时才增加。

 

短期持有一个mutex:  spin 循环255次一般可以有效以S mode获得一个mutex, 前提是该Mutex 已经被以S mode持有。 简单来说若有2个进程同时以S mode去申请一个Mutex,则稍晚的一个申请者需要进入SPIN并等稍早一点的申请者完成它的例如创建针对该mutex的一个reference的操作,但这都是非常迅速的操作。

 

长期持有一个Mutex: 如若一个Mutex已经被某进程以X mode持有, 则往往有其进程以SHRD模式去申请该mutex时仍发现该mutex 以X mode被其他进程所持有,则往往这个EXCL  持有是 LONG_EXCL(可以通过SSD DUMP发现),则后续的申请者往往要进入spin循环,甚至需要等待

 

上面我讲了willing-to-wait的mutex, 实际上mutex 的申请也可以是 nowait的。进程以nowait申请mutex时不会进入spin-cycle也不sleep,它只继续常规处理。 当一个nowait get失败时,将增加一次miss,但是实际上V$MUTEX_SLEEP_*中记录的miss不是这样的miss, 视图中记录的miss是等待的次数, 对于真正的miss没有统计项。

 

Wait Time等待时间

类似于latch,spin time 不算做mutex的消耗时间,它只包含等待消耗的时间。

 

真正理解Mutex相关的等待

 

Mutex数据结构中存放了Holder id持有者ID , Ref Count,和其他Mutex相关的统计信息。 Holder id对应于持有该Mutex的session id (v$session.sid)  。 特别注意, Ref Count是进程并发以S mode参考该Mutex的进程数量(如下文的演示)。

当一个Mutex被以X mode 持有,则Holder id 为对应持有该mutex的session id,而Ref Count为0。

 

每一个共享S mode持有者仅仅增加mutex上的Ref Count。 可供大量session并发以S mode持有参考一个Mutex。 但是注意更新ref count的操作是串行的, 这是为了避免错漏并维护mutex中正确的ref count。

 

下面我们详细介绍一个执行游标过程中对mutex share pin的过程:

  • 某进程以SHRD 模式申请一个Mutex,并尝试临时修改该Mutex的Holder ID
  • 若该Mutex正被他人更新,则该session会将Holder id设置为本session的sid,之后该进程将增加ref count,之后再清楚mutex上的Holder id。简单来说 这个Holder id是真正做了并行控制的功能。 若该Holder id 被设置了,则说明该Mutex要么被以EXCL模式持有,要么正有一个其他进程在以S mode申请该Mutex的过程中(例如更新Ref Count)。 当更新Ref Count时临时设置holder id的目的就是为了实现避免其他进程并发更新该Mutex的机制。 通过这些例子说明了 , Mutex既可以用作Latch并发控制, 也可用作pin。
  • 若Holder id已被设置,则申请进程将可能进入等待事件 。  例如若当前Mutex的持有者进程正以X mode更新该Mutex,则申请者的等待事件应为”cursor: pin S on X” 。  而若当持有者Holder并不是”真的要持有” 该Mutex,而仅仅是尝试更新其Ref Count,则第二个进程将等在’ Cursor :pin S’等待事件上; 实际正在更新Ref count的操作时很快的,是一种轻微的操作。 当第一个进程正在更新mutex,则后续的申请进程将进入spin 循环中255次等待前者结束。 当mutex上不再有 Holder id时(如前者的进程已经更新完Ref Count)时, 则申请者进程将Holder ID设为自身的SID,并更新Ref Count,并清除Holder id。 若在255次循环SPIN后mutex仍不被释放,则该进程进入等待并不再跑在CPU上。

 

 

 Mutex相关的等待事件

 

cursor: mutex * events等待事件

  • cursor: mutex * events等待事件用于Cursor Parent 和 Cursor stats类型的操作:
    • ‘cursor: mutex X’ , 某个进程申请以EXCL mode持有mutex时进入该等待, 该Mutex要么正被其他进程以SHRD模式参考,这导致X mode的申请必须要等待直到Ref count=0,  或者该mutex正被另一个进程以X mode持有。
    • 相关操作要求以EXCL X mode持有Mutex的:
      • 在一个父游标下创建一个新的子游标
      • 捕获SQL中的绑定变量
      • 更新或构件SQL统计信息V$SQLSTATS
  • ‘Cursor: Mutex S’ , 某个进程以SHRD S mode申请一个Mutex, 而该Mutex要么被其他进程已EXCL X mode所持有,要么其他进程正在更新mutex 上的Ref Count。
    • 相关类型的操作一般是检测父游标或者CURSOR统计信息数据, 此外查询V$SQLSTATS也会造成CURSOR statistics被查询

 

 

 

‘cursor: pin * events’等待事件

该类等待事件一般是为了pin相关的子游标

  • cursor: pin S  当一个进程以共享pin模式申请一个Mutex,而不能立即获得时,进入cursor: Pin S等待事件。 Mutex Pin是以共享类型的操作,例如执行一个游标。
    • 当一个进程等在cursor: pin S上,说明该进程在对一个共享的mutex pin 参考或取消参考时,有其他的进程也正在为同样的cursor heap创建或者取消一个共享Mutex pin。 实际上cursor: pin S 等待事件应当很少见,因为更新共享Mutex pin 的reference 应当是很快的。 再重复一次,S mode的Mutex可以被并发持有, 但是更新Mutex的Ref Count仍需要串行地处理 。 一旦reference count被增加好,则后续进程将可以为同样的cursor heap增加reference count。 因此此处mutex 即可以扮演Latch的角色(串行控制ref count的更新),又可以扮演pin的角色(ref count本身)。
  • ‘cursor: pin X’  当一个进程需要以EXCL X mode获得mutex时, 这类需要EXCL X 模式的串行操作包括:
    • 构建一个子游标
    • 某个进程已经以X mode持有该Mutex
    • 一个或多个进程正在reference 该Mutex (shared mutex pin)
  • ‘Cursor: pin S on X’ 最常见的等待事件,  进程为了共享操作例如执行pin游标而以SHRD S mode申请mutex, 但是未立即获得。原因是该游标被其他进程以EXCL X mode 持有了。

 

 Mutex的相关统计视图

 

V$MUTEX_SLEEP

 

shows the wait time, and the number of sleeps for each combination of mutex type and location.

 

Column Datatype Description
MUTEX_TYPE VARCHAR2(32) Type of action/object the mutex protects
LOCATION VARCHAR2(40) The code location where the waiter slept for the mutex
SLEEPS NUMBER Number of sleeps for this MUTEX_TYPE and LOCATION
WAIT_TIME NUMBER Wait time in microseconds

 

 

V$MUTEX_SLEEP_HISTORY

 

displays time-series data. Each row in this view is for a specific time, mutex type, location, requesting session and blocking session combination. That is, it shows data related to a specific session (requesting session) that slept while requesting a specific mutex type and location, because it was being held by a specific blocking session. The data in this view is contained within a circular buffer, with the most recent sleeps shown.

 

Column Datatype Description
SLEEP_TIMESTAMP TIMESTAMP(6) The last date/time this MUTEX_TYPE and LOCATION was slept for by theREQUESTING_SESSION, while being held by the BLOCKING_SESSION.
MUTEX_TYPE VARCHAR2(32) Type of action/object the mutex protects
GETS NUMBER The number of times the mutex/location was requested by the requesting session while being held by the blocking session. GETS is only incremented once per request, irrespective of the number of sleeps required to obtain the mutex.
SLEEPS NUMBER The number of times the requestor had to sleep before obtaining the mutex
REQUESTING_SESSION NUMBER The SID of a session requesting the mutex
BLOCKING_SESSION NUMBER The SID of a session holding the mutex
LOCATION VARCHAR2(40) The code location where the waiter slept for the mutex
MUTEX_VALUE RAW(4) If the mutex is held in exclusive (X) mode, this column shows the SID of the blocking session, else it shows the number of sessions referencing the mutex in S mode.
P1 NUMBER Internal use only
P1RAW RAW(4) Internal use only
P2 NUMBER Internal use only
P3 NUMBER Internal use only
P4 NUMBER Internal use only
P5 VARCHAR2(64) Internal use only

接着我们会在环境中模拟cursor pin S wait on X的场景,并通过systemstate dump和v$mutex_sleep , v$mutex_sleep_history等视图观察这一现象

 
session A:
SQL> select * from v$version;

BANNER
—————————————————————-
Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 – 64bi
PL/SQL Release 10.2.0.5.0 – Production
CORE 10.2.0.5.0 Production
TNS for Linux: Version 10.2.0.5.0 – Production
NLSRTL Version 10.2.0.5.0 – Production
www.askmac.cn

SQL> show parameter kks
SQL>
SQL> create table mac_kks tablespace users nologging as select * from dba_objects;

Table created.

SQL> insert /*+ append */ into mac_kks select * from mac_kks;

77386 rows created.

SQL> commit;

Commit complete.

SQL> insert /*+ append */ into mac_kks select * from mac_kks;

154772 rows created.

SQL> commit;

Commit complete.

SQL> insert /*+ append */ into mac_kks select * from mac_kks;

309544 rows created.

SQL> commit;

Commit complete.

SQL> insert /*+ append */ into mac_kks select * from mac_kks;

619088 rows created.

SQL> commit;

Commit complete.

SQL> insert /*+ append */ into mac_kks select * from mac_kks;

1238176 rows created.

SQL> commit;

Commit complete.

 

 
SQL> oradebug setmypid
Statement processed.
SQL> oradebug tracefile_name
Statement processed.
SQL> alter table mac_kks add t2 char(2000) default ‘MACLEAN’;

 

 

session B:
SQL> oradebug setospid 32424
Oracle pid: 17, Unix process pid: 32424, image: [email protected] (TNS V1-V3)
SQL> oradebug suspend;
Statement processed.

 

session C:

select * from mac_kks where rownum=1; ==> hang

session D:

select * from mac_kks where rownum=1; ==> hang

 

session E:

SQL> select sid,event from v$session where wait_class!=’Idle’;

SID EVENT
———- —————————————————————-
141 SQL*Net message to client
145 library cache lock
149 cursor: pin S wait on X
159 log buffer space

SQL> oradebug setmypid
Statement processed.

SQL> oradebug dump systemstate 266;
Statement processed.

SQL> oradebug tracefile_name
/s01/admin/G10R25/udump/g10r25_ora_32537.trc
Object Names
~~~~~~~~~~~~
LOCK: handle=a7115ef0
Mutex 7fff7abadecf

 

KGX Atomic Operation Log 0x8d88a8d8
Mutex 0x954eaff8(145, 0) idn 7fff7abadecf oper EXCL
Cursor Pin uid 145 efd 0 whr 1 slp 0
opr=3 pso=0x97951af0 flg=0
pcs=0x954eaff8 nxt=(nil) flg=35 cld=0 hd=0xa7864b08 par=0x9523a9e0
ct=0 hsh=0 unp=(nil) unn=0 hvl=9595c3d8 nhv=1 ses=0xa8416738
hep=0x954eb078 flg=80 ld=1 ob=0x95ac6128 ptr=0x8fd90128 fex=0x8fd8f438

0x954eaff8(145, 0) ==> sid和 ref count
pso ==> parent state object
hd=0xa7864b08 ==>cursor 对应的handle address
par ==> 父游标的heap 0 pointer
ses=0xa8416738 ==》 一般 EXCL是才有 session address v$session.saddr

SID=145 对Mutex 0x954eaff8 oper EXCL以X mode Hold 该Mutex, SID=145 在等 SYS.MAC_KKS表的library cache lock,该表被X mode pin和lock,而解析SQL要求以S mode lock该表

SID=149 对Mutex 0x954eaff8 申请 oper GET_SHRD, SID=149在等cursor: pin S wait on X

KGX Atomic Operation Log 0x8db79798
Mutex 0x954eaff8(145, 0) idn 7fff7abadecf oper GET_SHRD
Cursor Pin uid 149 efd 0 whr 5 slp 13893
opr=2 pso=0x8e6bd518 flg=0
pcs=0x954eaff8 nxt=(nil) flg=35 cld=0 hd=0xa7864b08 par=0x9523a9e0
ct=0 hsh=0 unp=(nil) unn=0 hvl=9595c3d8 nhv=1 ses=0xa8416738
hep=0x954eb078 flg=80 ld=1 ob=0x95ac6128 ptr=0x8fd90128 fex=0x8fd8f438

SO: 0xa841bd18, type: 4, owner: 0xa830cf98, flag: INIT/-/-/0x00
(session) sid: 149 trans: (nil), creator: 0xa830cf98, flag: (80000041) USR/- BSY/-/-/-/-/-
DID: 0001-0019-00000066, short-term DID: 0000-0000-00000000
txn branch: (nil)
oct: 0, prv: 0, sql: 0x8d88bf90, psql: (nil), user: 0/SYS
service name: SYS$USERS
O/S info: user: oracle, term: pts/5, ospid: 32510, machine: vrh8.oracle.com
program: [email protected] (TNS V1-V3)
application name: [email protected] (TNS V1-V3), hash value=543908804
waiting for ‘cursor: pin S wait on X’ wait_time=0, seconds since wait started=0
idn=7abadecf, value=9100000000, where|sleeps=500003645
blocking sess=0x(nil) seq=13901
Dumping Session Wait History
for ‘cursor: pin S wait on X’ count=1 wait_time=0.266596 sec
idn=7abadecf, value=9100000000, where|sleeps=500003644
for ‘cursor: pin S wait on X’ count=1 wait_time=0.010679 sec
idn=7abadecf, value=9100000000, where|sleeps=500003643
for ‘cursor: pin S wait on X’ count=1 wait_time=0.010633 sec
idn=7abadecf, value=9100000000, where|sleeps=500003642
for ‘cursor: pin S wait on X’ count=1 wait_time=0.010843 sec
idn=7abadecf, value=9100000000, where|sleeps=500003641
for ‘cursor: pin S wait on X’ count=1 wait_time=0.011008 sec
idn=7abadecf, value=9100000000, where|sleeps=500003640
for ‘cursor: pin S wait on X’ count=1 wait_time=0.010406 sec

 

 

SO: 0xa8416738, type: 4, owner: 0xa830bfa8, flag: INIT/-/-/0x00
(session) sid: 145 trans: (nil), creator: 0xa830bfa8, flag: (80000041) USR/- BSY/-/-/-/-/-
DID: 0001-0017-0000008E, short-term DID: 0000-0000-00000000
txn branch: (nil)
oct: 3, prv: 0, sql: 0x8d88bf90, psql: (nil), user: 0/SYS
service name: SYS$USERS
O/S info: user: oracle, term: pts/4, ospid: 32485, machine: vrh8.oracle.com
program: [email protected] (TNS V1-V3)
application name: [email protected] (TNS V1-V3), hash value=543908804
waiting for ‘library cache lock’ wait_time=0, seconds since wait started=165
handle address=a7115ef0, lock address=978def20, 100*mode+namespace=c9
blocking sess=0x(nil) seq=9
Dumping Session Wait History
for ‘library cache lock’ count=1 wait_time=3.297287 sec
handle address=a7115ef0, lock address=978def20, 100*mode+namespace=c9
for ‘library cache lock’ count=1 wait_time=2.930321 sec
handle address=a7115ef0, lock address=978def20, 100*mode+namespace=c9
for ‘library cache lock’ count=1 wait_time=2.930856 sec
handle address=a7115ef0, lock address=978def20, 100*mode+namespace=c9
for ‘library cache lock’ count=1 wait_time=2.930698 sec
handle address=a7115ef0, lock address=978def20, 100*mode+namespace=c9
for ‘library cache lock’ count=1 wait_time=2.931518 sec
handle address=a7115ef0, lock address=978def20, 100*mode+namespace=c9

SO: 0x978def20, type: 53, owner: 0xa8456058, flag: INIT/-/-/0x00
LIBRARY OBJECT LOCK: lock=978def20 handle=a7115ef0 request=S
call pin=(nil) session pin=(nil) hpc=0005 hlc=0000
htl=0x978defa0[0x8e4a8950,0x8e4a8950] htb=0x8e4a8950 ssga=0x8e4a7a88
user=a8416738 session=a8416738 count=0 flags=RES/[0010] savepoint=0x1f
LIBRARY OBJECT HANDLE: handle=a7115ef0 mtx=0xa7116020(0) lct=8 pct=10 cdp=0
name=SYS.MAC_KKS
hash=c066b9b9c6c80736a15f5ba325563fdb timestamp=04-14-2013 00:43:14
namespace=TABL flags=KGHP/TIM/SML/[02000000]
kkkk-dddd-llll=0000-0701-0201 lock=X pin=X latch#=3 hpc=0006 hlc=0004
lwt=0xa7115f98[0x978def50,0x978def50] ltm=0xa7115fa8[0xa7115fa8,0xa7115fa8]
pwt=0xa7115f60[0xa7115f60,0xa7115f60] ptm=0xa7115f70[0xa7115f70,0xa7115f70]
ref=0xa7115fc8[0xa7115fc8,0xa7115fc8] lnd=0xa7115fe0[0x9cc2c260,0xa79fd198]
LIBRARY OBJECT: object=95f0e5b0
type=TABL flags=EXS/LOC/UPD[0905] pflags=[0000] status=VALD load=0
DATA BLOCKS:
data# heap pointer status pins change whr
—– ——– ——– ——— —- —— —
0 a78d3840 95f0e708 I/P/A/-/- 0 NONE 00
8 957a6ad8 94461f88 I/P/A/-/- 1 UPDATE 00

Mutex 0x954eaff8 被 SID=145 oper EXCL以X mode Hold 该Mutex

体现为 子游标child cursor被以 X mode pin
SO: 0x8e6bd518, type: 53, owner: 0xa841bd18, flag: INIT/-/-/0x00
LIBRARY OBJECT LOCK: lock=8e6bd518 handle=a7864b08 mode=N
call pin=(nil) session pin=(nil) hpc=0000 hlc=0000
htl=0x8e6bd598[0x8e542f60,0x979da4d0] htb=0x979da4d0 ssga=0x979d96c8
user=a841bd18 session=a841bd18 count=1 flags=CBK[0020] savepoint=0x0
LIBRARY OBJECT HANDLE: handle=a7864b08 mtx=0xa7864c38(0) lct=2 pct=3 cdp=0
namespace=CRSR flags=RON/KGHP/PN0/EXP/[10010100]
kkkk-dddd-llll=0000-0001-0001 lock=N pin=X latch#=3 hpc=0002 hlc=0002
lwt=0xa7864bb0[0xa7864bb0,0xa7864bb0] ltm=0xa7864bc0[0xa7864bc0,0xa7864bc0]
pwt=0xa7864b78[0xa7864b78,0xa7864b78] ptm=0xa7864b88[0xa7864b88,0xa7864b88]
ref=0xa7864be0[0x954eb320,0x954eb320] lnd=0xa7864bf8[0xa7864bf8,0xa7864bf8]
LIBRARY OBJECT: object=95ac6128
type=CRSR flags=EXS[0001] pflags=[0000] status=VALD load=0
DATA BLOCKS:
data# heap pointer status pins change whr
—– ——– ——– ——— —- —— —
0 8d81aa70 95ac6240 I/P/A/-/- 0 NONE 00
6 954eb0f0 8fd90128 I/P/A/-/E 0 NONE 00

并行执行6个SQL语句 并做systemstate dump :

 

[oracle@vrh8 ~]$ grep SHRD /s01/admin/G10R25/udump/g10r25_ora_32716.trc |grep 0x95987388
Mutex 0x95987388(0, 6) idn 7fff8f32fff6 oper SHRD
Mutex 0x95987388(0, 6) idn 7fff8f32fff6 oper SHRD
Mutex 0x95987388(0, 6) idn 7fff8f32fff6 oper SHRD
Mutex 0x95987388(0, 6) idn 7fff8f32fff6 oper SHRD
Mutex 0x95987388(0, 6) idn 7fff8f32fff6 oper SHRD
Mutex 0x95987388(0, 6) idn 7fff8f32fff6 oper SHRD

 

 

to be continued ……………………………


Posted

in

by

Tags:

Comments

10 responses to “深入理解Oracle中的Mutex”

  1. 俞鸿钧 Avatar

    你好MACLEAN,想就您的实验问两个问题,实验中session E捕获到了两个主要的event,145 library cache lock和149 cursor: pin S wait on X,SID为145的event是不是由于sessionB的挂起操作引起的?SID为149的event是不是由sessionCD引起的?因为sessionCD分别使用了select语句并被挂住了,那么dump文件中是不是会有ref count=2的信息?

  2. Ask_Maclean_liu_Oracle Avatar

    Latch和 10.2.0.3后引入的KGX Mutex对比 和 latch一样, kgx mutex也是用来控制串行化访问SGA中数据的 ,但仍有一些重要区别:KGX mutex要比 CAS latch更轻量级, mutex 结构大约为16个字节, 而一个latch结构大约是100个字节。 因此 mutex嵌入到大量其他对象结构中是可行的, 因为他的struct 足够小之所以mutex可以提供 更小的结构 很廉价的成本,其原因是 使用mutex有一个简单的前提假设: 对于mutex的争用是很小的。 因此没有为mutex那样提供一个优化过的wait list , mutex做更多的 SPIN & WAIT 并消耗更多的CPU。 此外mutex也没有提供任何死锁检测和预防机制,这些都完全取决于Kgx mutex的用户自身的行为。Latch在 内部视图(例如X$KSLLT)中提供 全面的诊断信息。 KGX mutex在(x$mutex_sleep、x$mutex_sleep_history等内部视图)中提供部分信息, 同时也允许其用户在回调程序中用特定信息填充这些视图。除了共享和排他模式之外, KGX mutex还提供一种examine 模式, 允许其在不以共享或排他模式持有mutex的情况下client检查一个mutex的状态以及其用户数据。 这种模式是latch所没有的

  3. 或者是2012 Avatar
    或者是2012

    抽象!

  4. Ask_Maclean_liu_Oracle Avatar

    ‘cursor:mutex ..’/ ‘cursor:pin ..’/ ‘library cache:mutex ..’类型的等待事件 (Doc ID 1525791.1)适用于:Oracle Database – Enterprise Edition – 版本 10.1.0.2 和更高版本Oracle Database – Standard Edition – 版本 10.1.0.2 和更高版本Oracle Database – Personal Edition – 版本 10.1.0.2 和更高版本本文档所含信息适用于所有平台用途本文章针对与CURSOR(游标)管理活动相关的等待事件提供了一些核心要点信息。问题和答案什么是 ‘cursor: ‘ 等待事件?处理或访问cursor的任何操作都可能需要等待,才能访问在 shared pool 中支持这些操作的结构。在极限争用的情况下,这些等待事件就会成为一个显著瓶颈,继而束缚正常活动。从版本 10.2 开始,一些共享cursor操作开始由 Oracle 的 Mutex 功能实施,在 11g 中 Librarycache 和 rowcache 组件也通过 Mutex 实施。最常见的等待事件是什么?最常见的等待事件包括:cursor: mutex Xcursor: mutex Scursor: pin Xcursor: pin Scursor: pin S wait on Xlibrary cache: mutex Xlibrary cache: mutex S请注意,所有这些等待事件都非常相似,并且可能都是在一个操作过程中产生的等待。eXclusive(排他)操作是需要更改特定结构的那些操作;Share(共享)操作可以在不更改的情况下进行,只是需要在更改过程中暂时锁定这些操作,以防止其被其他项更改。这点区别实际对于问题的诊断并没有太多关联,只是特定等待事件可能在特定问题中更为常见。 等待事件最常见的原因是什么?基于这些事件的争用通常是另一个问题的症状表现 – 即问题是其它地方产生的,而不是 mutex 机制本身。如果需要解决 mutex 竞争这个问题表现,我们需要识别问题根本原因并加以处理。Cursor 相关等待事件是 SQL 语句在 parse 时产生的,包括将cursor加载到 shared pool 中或在其中搜索那些cursor。出现这些问题可能的原因:shared pool 中 cursor 的版本数变得过多过多的硬/软分析过多的无效/重新加载加载了大量的对象shared pool 大小不合适资源的持有者被 OS 或者 Resource Manager 从 CPU 上移除内存的操作系统管理(例如 Linux x86-64 上非常大的 SGA,而没有实施 Hugepage)代码缺陷如果 cursor 共享的很好,并且 child cursor 和版本数量较低,那么一般不会产生这种类型的争用。如何避免这些等待事件?通常,通过采用合理的cursor共享策略,正确使用绑定变量并确保没有大量版本,应该能够避免大多数这类性质的问题。有用的文章包括:Note:62143.1 Understanding and Tuning the Shared PoolNote:94036.1 Init.ora Parameter “CURSOR_SHARING” Reference Note如果您发现自己有大量 cursor 版本,参阅以下文章可能会有所帮助:Note:296377.1 Troubleshooting: High Version Count IssuesNote:438755.1 Formated V$SQL_SHARED_CURSOR Report by SQLID or Hash Value 可以在什么位置找到原因诊断以及关于这些等待事件的更多信息?常见诊断因为这些等待事件具有相似的原因,因此有些诊断信息对所有的等待都适用:问题的历史记录因为这些等待事件具有相似的原因,因此有些诊断信息对所有的等待都适用:最近更改了什么?应用程序、数据库、中间件层更改OS 更改负载的增加共性或因果关系是否有任何特定事件看起来会触发问题?问题是否总在特定时间段发生?诊断依据通常需要进行大量诊断才能确定问题。这是因为这类等待事件是一种症状表现,阻塞会话可能与等待会话没有任何关系,只是它碰巧将后者阻塞而已。AWR(或 Statspack)和 ASH 报表(用于等待会话)这些提供了系统概览并且还根据需要关注了单个会话Stack trace(s) 堆栈跟踪通过 stack trace 我们可以看到资源持有者正在处理的代码区域。如果无法找到资源持有者:收集包含 short stack dump 的Systemstate dump(收集关于每个会话的信息应该可以捕获到持有者)如果无法标识持有者:收集等待者的 Errorstack操作系统统计信息(例如 OSWatcher)操作系统统计信息非常有用的原因有多种,如标识高 CPU 用户、找出活动的高峰,以及标识“构建”符号来帮助触发早期的数据捕获。请注意,在具有大量会话的忙碌系统上获取 systemstate 可能需要很大开销。如果是这种情况,则可考虑生成不同的 dump ,但是这些 dump 提供的信息会减少,可能不足以进一步诊断问题。所以,按照最有用(且最大开销)的信息从高到低排序,请尝试获取:级别 266 的 Systemstate(包含堆栈的 Systemstate)级别 258 的 Systemstate(包含堆栈不太详细的 Systemstate)具有堆栈跟踪的 Hanganalyze 输出例如,如果级别 266 systemstate 开销太大,则您可以尝试使用级别 258。您还可以合并上述各项。例如,获取一个级别 266 systemstate 和多个 hanganalyze dump。(hanganalyze dump应该包括 short stack dump)。数据收集参考资料:Note:1363422.1 AWR Reports – Information Center Note:748642.1 How to Generate an AWR Report and Create Baselines [ID 748642.1]Note:1364257.1 How to Collect Errorstacks for use in Diagnosing Performance Issues.Note:452358.1 Database Hangs: What to collect for support.Note:175006.1 Steps to generate HANGANALYZE trace files.Note:301137.1 OS Watcher User GuideNote:1360119.1 FAQ: Database Performance Frequently Asked Questionscursor: mutex X一个 cursor 正在被parse 并尝试以 eXclusive 模式获取 cursor mutexcursor: mutex S一个 cursor 正在被parse并尝试以 Share 模式获取 cursor mutexNote:9591812.8 Bug 9591812 – Wrong wait events in 11.2 (“cursor: mutex S” instead of “cursor: mutex X”)cursor: pin X一个 cursor 正在被parse 并尝试以 eXclusive 模式获取cursor pincursor: pin S一个 cursor 正在被parse并尝试以 Share 模式获取cursor pin。请参阅:Note:1310764.1 WAITEVENT: “cursor: pin S” Reference Note如果在此事件中发现争用,最好查找其他相关等待事件并首先对其进行调查,因为这个等待很有可能只是其它争用的症状。cursor: pin S wait on X一个 cursor 正在被parse 并持有了 cursor pin,而且尝试在 eXclusive 模式下获取该 cursor pin。如果在 AWR的“Top Waits”部分看见 ‘cursor: pin S wait on X’ 突出显示,如下所示:则应该首先查看您在系统中具有的 cursor 版本数:如果它们接近此处显示的异常高的数量,则根据优先级减少 cursor 版本。请参阅:Document 296377.1 Troubleshooting: High Version Count Issues如果不是这个原因导致的,您可以使用下列文章帮助排除问题:Note:1349387.1 Troubleshooting ‘cursor: pin S wait on X’ waitsNote:1298015.1 WAITEVENT: “cursor: pin S wait on X” Reference NoteNote:786507.1 How to Determine the Blocking Session for Event: ‘cursor: pin S wait on X’ Note:742599.1 High ‘cursor: pin S wait on X’ and/or ‘library cache lock’ Waits Generated by Frequent Shared Pool/Buffer Cache Resize ActivityNote:1268724.1 “Cursor: Pin S Wait On X” Contention Mutex Sleep Reason Primarily ‘ kkslce [KKSCHLPIN2]’Note:402027.1 Bug:5653007; 5485914: SELF DEADLOCK PROCESS WAITS ON ”Cursor: Pin S Wait On X” with SQL_TRACE enabled.Note:9472669.8 Bug 9472669 – ‘cursor: pin S wait on X’ waits for invalid SQL over DB linklibrary cache: mutex X此处将执行 library cache 操作并尝试在 eXclusive 模式下获取 library cache mutex。”library cache:mutex X” 症状非常常见,很多问题都会导致该症状,所以完全理解根本原因以便确定正确的操作是非常重要的。在大多情况中,可以通过对应用程序进行更改(例如阻止登录或注销风暴)来减轻问题。还有可能是遇到了已知 Oracle bug(这包括与互斥相关的问题,以及具有互斥等待事件症状的非互斥问题)。Note:1357946.1 Troubleshooting ‘library cache: mutex X’ waits.Note:727400.1 WAITEVENT: “library cache: mutex X”Note:758674.1 ” Library Cache: Mutex X ” On Koka Cursors (LOBs) Non-Shared :Note:9530750.8 Bug 9530750 – High waits for ‘library cache: mutex X’ for cursor Build locklibrary cache: mutex S此处将执行 library cache 操作并尝试在 Share 模式下获取 library cache mutex有用参考 Note:34579.1 WAITEVENT: “library cache pin” Reference Note

  5. Didodb Avatar
    Didodb

    请问11g到19c,Mutex结构做了什么样的调整,观察到同样的业务代码和并发压力下,19c更容易遇到Mutex的并发问题

Leave a Reply to cursor: mutex X等待事件 – ORACLE数据库数据恢复、性能优化、故障诊断来问问MACLEAN Cancel reply

Your email address will not be published. Required fields are marked *