2.3 Library Cache
2.3.1 Library Cache与SQL游标
Library Cache主要用于存放SQL游标,而SQL游标最大化共享是Library Cache优化的重要途径,可以使SQL运行开销最低、性能最优。
- SQL语句与父游标及子游标
在PL/SQL中,游标(Cursor)是数据集遍历的内存集合。而从广义上讲,游标是SQL语句在Library Cache中的内存载体。SQL语句与游标关系如下:
1)一条SQL语句包含一个父游标(Parent Cursor)和一至多个子游标(Child Cursor),如图2-2所示。
图2-2 SQL语句与游标
2)SQL语句通过SQL_ID唯一标识父游标,如下所示:
从上述示例可以看出,SQL语句使用SQL_ID唯一标识父游标(V$SQLAREA),同时该SQL语句仅包含一个父游标和一个子游标。
3)不同的SQL语句的父游标也不同,如下所示:
可以看出,两个不同SQL语句对应的SQL_ID也不相同,产生了不同的父游标。
SQL语句父游标不相同,其对应的子游标也肯定不同。关于游标内存结构介绍,可以参考5.1节。
2.父游标
(1)父游标特点
父游标的主要特点如下:
父游标是由SQL语句决定的;
父游标使用SQL语句的SQL_ID唯一标识;
父游标包含一到多个子游标;
父游标与参数cursor_sharing紧密相关。
(2)父游标组成结构
父游标的主要组成结构如表2-2所示。
父游标组成结构单元之间的关系,如图2-3所示。
图2-3 父游标组成结构
(3)父游标相关查询
父游标信息可以通过V$SQLAREA视图进行查询。V$SQLAREA的主要特点有:
V$SQLAREA中一条记录表示一个父游标,如下所示:
可以看出在V$SQLAREA视图中,SQL_ID是唯一的,从侧面也可以证明V$SQL-AREA中一条记录代表一个父游标。
V$SQLAREA只包含父游标的相关信息。
(4)父游标相关参数
参数cursor_sharing决定父游标被共享的模式,用于减少解析带来的开销,提升SQL执行效率。cursor_sharing的3种模式如下:
EXACT(默认模式),如下所示:
FORCE;
SIMILAR。
接下来对这3种模式进行详细介绍。
1)cursor_sharing= EXACT:默认模式。只有SQL语句内容完全一样,才会共享父游标(SQL语句之间才会共享)。也就是说,当用户端发起的SQL语句只要有一点不相同,就会产生不同的父游标,从而不会共享SQL父游标。如下所示:
2)cursor_sharing = FORCE:当模式设置为FORCE时,将会强制优化器共享父游标,而不管执行计划是否最优。当条件允许时,可以采用这种方式来减少解析开销。如下所示:
可以看出,在FORCE模式下,两条内容不同的SQL强制共享了父游标(使用系统绑定变量)。
FORCE模式建议不要过度使用,虽然这种模式会强制SQL共享父游标,但是这样可能会忽略CBO优化器最优的执行计划,使得SQL执行不是最优化的。
3)cursor_sharing = SIMILAR:模式SIMILAR表示优化器在一定条件下会自动选择共享游标:
SQL语句几乎完全相同;
执行计划相同或者执行计划更优;
忽略SQL语句文字内容差异。
可以通过以下示例进行验证。
示例1:参数变化导致游标共享差异。
可以看出,当模式设置为SIMILAR时,只要SQL语句相似就可以共享游标 。
示例2可以概括为如图2-4所示的关系。
通过图2-4可以看到,一个父游标可以包含多个子游标,从而验证了图2-2的正确性。
3.子游标
(1)子游标特点
子游标的主要特点有:
V$SQL中一条记录对应一个子游标;
子游标与绑定变量(Bind Variable)、NLS参设置等相关;
子游标与参数optimizer_mode紧密相关。
(2)子游标组成结构
子游标的主要组成结构如表2-3所示。
图2-5 子游标组成结构
有关父子游标的详细信息,可以参考5.1节。
(3)子体游标相关查询
子游标信息可以通以V$SQL(X$KGLCURSOR_CHILD)视图进行查询。V$SQL的主要特点有:
V$SQL中一条记录代表一个子游标。如下所示:
可以看到,一个SQL_ID(父游标)包含了多条记录,每条记录代表一个子游标。
V$SQL包含了父游标和子游标信息。
(4)子游标相关参数
参数optimizer_mode用于设置子游标的CBO优化器模式。可以通过查询V$SQL_SHARED_CURSOR. OPTIMIZER_MISMATCH验证子游标不匹配(missmatch)的原因:是否由参数optimizer_mode导致。如下所示:
可以将上面内容概括为如图2-6所示的关系。
参数optimizer_mode相关设置可参考6.1.1节。
2.3.2 Library Cache内存结构
- Library Cache内存结构概览
Oracle使用内存管理器(KGH)对Library Cache内存进行管理。Library Cache包含了一张由Hash Bucket组成的Hash Table,每个Hash Bucket以链表的方式与Object Handle进行链接,如图2-7所示,ObjectHandle主要负责Library Cache Lock(Pin)控制;同时,Object Handle指向LCO(Library Cache Object),LCO由各种类型的对象组成,如图2-8所示。
图2-7 Hash Table与Object Handle
图2-8 Object Handle与LCO
- Library Cache内存相关参数
参数_kgl_buckets_count决定了(Library Cache)Hash Bucket的数量,可以通过调节该参数来对(Library Cache)Hash Table进行调节。Hash Table的主要特点:
Hash Table会自动扩展:当所需的Bucket的数量超过当前Hash Table中可容纳的空间时进行扩展;
Hash Table自动扩展的原则为:上一次分配空间的两倍左右;
Hash Table扩展将会分配新的Hash Table来替换掉当前的Hash Table,同时将原Hash Table中的Hash Bucket重新“哈希”到新的Hash Table,最后释放原Hash Table内存;
参数_kgl_buckets_count与Hash Bucket关系如下所示:
Hash Bucket的数量为2的_kgl_bucket_count次方与256的乘积。
我们可以通过以下示例进行验证。
1)查看参数_kgl_buckets_count的配置,如下所示:
2)查看Library Cache的内存分配情况,如下所示:
可以看到:
LIBRARY CACHE HASH TABLE中的size(131072)为Hash Bucket的数量,count (6394)为LCO Handle的数量;
131072=29×256,与公式完全符合;
131072=124829(Chain_Size:0)+6092(Chain_Size:1)+151(Chain_Size:2)。
Hash Bucket是由Hash_Chain_Size不同的Hash_Chain组成的,这样的好处是可以提高Library Cache空间使用率,减少内存碎片的产生。
- Library Cache Dump
Library Cache Dump内容如下所示:
可以看出,Library Cache是由Hash Buckte、LCO Handle以及LCO 等内存结构组成的。
2.3.3 Library Cache Lock(Pin)
- Library Cache Lock(Pin)概述
(1)Library Cache Lock特点
Library Cache包含了SQL解析树、执行计划以及被引用的对象等信息。同时,Library Cache还包含了同义词转换、依赖关系信息以及LCO/LCO Handle等结构。这些信息结构在PL/SQL编译、SQL语句解析执行等场景使用Library Cache Lock进行保护。Library Cache Lock主要特点有:
Library Cache Lock被称为易破坏的解析锁(Parse Lock),负责对SQL/PLSQL解析树(LCO Handle)以及依赖对象进行保护;
Library Cache Lock在SQL/PLSQL解析到内存时为共享(Share)模式,然后以Null模式存在;
如果SQL/PLSQL的相关(引用)对象定义被更改而导致解析树发生变化,Oracle就会破坏Library Cache Lock的锁定,对引用的LCO进行无效化(Invalidate)处理。在下次调用SQL/PSQL时,需要重新解析、缓存,从而降低了数据库的性能;
Library Cache Lock只有在解析树引用的LCO对象还没有被Pin入内存时才能被破坏。当这些被解析树引用的LCO对象被Pin住后,Library Cache Lock将升级为Excluseive模式,这时就不能对Library Cache Lock进行破坏操作,保护了Library Cache结构的完整性。
(2)Library Cache Pin特点
Library Cache Pin发生在Library Cache Lock之后,在SQL/PLSQL执行操作时产生Pin。Library Cache Pin的主要特点如下:
Library Cache Pin负责对Heap0对象(LCO)以及依赖对象进行保护;
Library Cache Pin是SQL/PLSQL执行调用时产生Pin;
LCO被Pin,其引用的数据库对象都将被Pin;
Library Cache解析树引用的数据库对象被Pin时,其对应的数据字典锁(Row Cache Enqueue Lock)就会保护这些数据库对象,防止DDL破坏;
Library Cache Pin一般是Share模式,当需要修改LCO时,就需要转换成Exclusive独占模式。
(3)Library Cache Lock(Pin)用途
Library Cache Lock(Pin)的主要用途如下:
Library Cache Lock管理并发控制;
Library Cache Pin保证内存数据完整性。
Library Cache Lock在解析、调用等场景被获取,Library Cache Pin在编译、执行等场景被获取,它们的主要用途是保护解析树以及内存数据对象的完整性。
- Library Cache Lock(Pin)持续性
Library Cache Lock(Pin)持续性分为以下几种级别:
会话级(Session):Library Cache Lock(Pin)持续到会话结束;
事务级(Transaction):Library Cache Lock(Pin)持续到事务Commit/Rollback时释放;
调用级(Call):Library Cache Lock(Pin)持续到Call结果返回时释放。
- Library Cache Lock(Pin)模式
(1)Library Cache Lock模式
Library Cache Lock有3种模式:
共享模式(S):读取对象;
排他模式(X):修改对象;
空模式(Null):释放状态。
持久存储的对象可以处于上述3种锁定模式,临时对象(Cursor)只能处于Null锁定模式。
(2)Library Cache Pin模式
Library Cache Pin只有2种模式:
共享模式(S):读取LCO对象;
排他模式(X):更改LCO对象。
与Library Cache Lock锁定模式不同,持久存储对象和临时对象都可以用S、X模式Pin在内存中。
- Library Cache Lock(Pin)争用
当Library Cache Lock(Pin)处于排他模式(X)时,若其他Session需要对该Library Cache Lock(Pin)锁定的对象进行修改,就会产生Library Cache Lock(Pin)争用,对数据库库系统性能产生负面影响。
Library Cache Lock(Pin)争用的主要原因如下:
过量的解析:
SQL没有共享;
不必要的软解析;
没有合理使用绑定变量。
共享SQL被释放出Library Cache。
没有Pin住频繁使用的SQL/PLSQL对象。
参数设置不合理:参数session_cached_cursors的值设置过高。Library Cache可能保留大量无效且不被解析的Cursor,将有用的、共享的SQL“刷”出了Library Cache,导致SQL解析争用频繁。
- Library Cache Lock(Pin)优化
Library Cache Lock(Pin)争用优化最重要的思路就是增加SQL共享,主要考虑以下几个方面:
合理使用绑定变量,增加SQL共享,减少解析;
考虑使用DBMS_SHARED_POOL Pin住频繁使用的SQL/PLSQL对象;
减少对PLSQL/VIEW/PACKAGE等对象的编译/重编译操作;
减少PLSQL/VIEW/PACKAGE等对象的无效化(Invalidate)操作;
合理使用参数cursor_sharing/optimizer_mode,增加SQL共享;
合理设置参数session_cached_cursors,优化SQL解析(参考5.1节)。