虽然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。
原文转自:http://blogread.cn/it/article/6410