首页 >数据库 >mysql教程 >buffercache和sharedpool详解(之三,sharedpool原理)

buffercache和sharedpool详解(之三,sharedpool原理)

WBOY
WBOY原创
2016-06-07 15:59:331478浏览

【深入解析--eygle】 学习笔记 1.2 shared pool原理 Shared Pool是Oracle SGA设置中最复杂也是最重要的一部分内容,Oracle通过Shared Pool来实现SQL共享、减少代码硬解析等,从而提高数据库的性能。在某些版本中,如果设置不当,Shared Pool可能会极大影响数

【深入解析--eygle】 学习笔记

1.2 shared pool原理

Shared Pool是Oracle SGA设置中最复杂也是最重要的一部分内容,Oracle通过Shared Pool来实现SQL共享、减少代码硬解析等,从而提高数据库的性能。在某些版本中,如果设置不当,Shared Pool可能会极大影响数据库的正常运行。

在Oracle 7之前,Shared Pool并不存在,每个Oracle连接都有一个独立的Server进程与之相关联,Server进程负责解析和优化所有SQL和PL/SQL代码。典型的,在OLTP环境中,很多代码具有相同或类似的结构,反复的独立解析浪费了大量的时间以及资源,Oracle最终认识到这个问题,并且从PL/SQL开始尝试把这部分可共享的内容进行独立存储和管理,于是Shared Pool作为一个独立的SGA组件开始被引入,并且其功能和作用被逐渐完善和发展起来。

在这里注意到,Shared Pool最初被引入的目的,也就是它的本质功能在于实现共享。如果用户的系统代码是完全异构的(假设代码从不绑定变量,从不反复执行),那么就会发现,这时候Shared Pool完全就成为了一个负担,它在徒劳无功地进行无谓的努力:保存代码、执行计划等期待重用,并且客户端要不停的获取Latch,试图寻找共享代码,却始终一无所获。如果真是如此,那这是我们最不愿看到的情况,Shared Pool变得有害无益。当然这是极端,可是在性能优化中我们发现,大多数性能低下的系统都存在这样的通病:代码极少共享,缺乏或从不实行变量绑定。优化这些系统的根本方法就是优化代码,使代码(在保证性能的前提下)可以充分共享,减少无谓的反复硬/软解析。

实际上,Oracle引入Shared Pool就是为了帮助我们实现代码的共享和重用。了解了这一点之后,我们在应用开发的过程中,也应该有意识地?高自己的代码水平,以期减少数据库的压力。这应该是对开发人员最基本的要求。

Shared Pool主要由两部分组成,一部分是库缓存(Library Cahce),另一部分是数据字典缓存(Data Dictionary Cache)Library Cache主要用于存储SQL语句、SQL语句相关的解析树、执行计划、PL/SQL程序块(包括匿名程序块、存储过程、包、函数等)以及它们转换后能够被Oracle执行的代码等,这部分信息可以通过v$librarycache视图查询;至于Data Dictionary Cache主要用于存放数据字典信息,包括表、视图等对象的结构信息,用户以及对象权限信息,这部分信息相对稳定,在Shared Pool中通过字典缓存单独存放,字典缓存的内容是按行(Row)存储的(其他数据通常按Buffer存储),所以又被称为Row Cache,其信息可以通过V$ROWCACHE查询。

17:44:15 sys@felix SQL>desc v$librarycache;

Name Null? Type

---------------------------- ---------------------------------

NAMESPACE VARCHAR2(64)

GETS NUMBER

GETHITS NUMBER

GETHITRATIO NUMBER

PINS NUMBER

PINHITS NUMBER

PINHITRATIO NUMBER

RELOADS NUMBER

INVALIDATIONS NUMBER

DLM_LOCK_REQUESTS NUMBER

DLM_PIN_REQUESTS NUMBER

DLM_PIN_RELEASES NUMBER

DLM_INVALIDATION_REQUESTS NUMBER

DLM_INVALIDATIONS NUMBER

 

17:44:40 sys@felix SQL>

 

17:44:40 sys@felix SQL>desc v$rowcache;

Name Null? Type

------------------------------ -------------------------------

CACHE# NUMBER

TYPE VARCHAR2(11)

SUBORDINATE# NUMBER

PARAMETER VARCHAR2(32)

COUNT NUMBER

USAGE NUMBER

FIXED NUMBER

GETS NUMBER

GETMISSES NUMBER

SCANS NUMBER

SCANMISSES NUMBER

SCANCOMPLETES NUMBER

MODIFICATIONS NUMBER

FLUSHES NUMBER

DLM_REQUESTS NUMBER

DLM_CONFLICTS NUMBER

DLM_RELEASES NUMBER

 

17:50:55 sys@felix SQL>

 

下图说明了Shared Pool各个部分协同工作以及与Buffer Cache的配合。

 

 

从Oracle Database 11g开始,在Shared Pool中划出了另外一块内存用于存储SQL查询的结果集,称为ResultCache Memory。以 前Shared Pool的主要功能是共享SQL,减少硬解析,从而?高性能,但是SQL共享之后,执行查询同样可能消耗大量的时间和资源,现在Oracle尝试将查询的结果集缓存起来,如果同一SQL或PL/SQL函数多次执行(特别是包含复杂运算的SQL), 那 么 缓 存 的查 询 结 果 可 以 直 接 返 回给用户,不需要真正去执行运算,这样就又为性能带来了极大的提升。

1.2.1 Oracle 11g 新特性:Result Cache

结果集缓存(Result Cache)是Oracle Database 11g新引入的功能,除了可以在服务器端缓存结果集(ServerResult Cache)之外,还可以在客户端缓存结果集(Client Result Cache)。

服务器端的Result Cache Memory由两部分组成:

(1) SQL Query Result Cache:存储SQL查询的结果集。

(2) PL/SQL Function Result Cache:用于存储PL/SQL函数的结果集。

Oracle通过一个新引入初始化参数result_cache_max_size 来控制该Cache的大小。如果result_cache_max_size=0 则表示禁用该特性。参数result_cache_max_result 则控制单个缓存结果可以占总的ServerResult Cache大小的百分比。

09:47:20 sys@felix SQL>show parameter result_

NAME TYPE VALUE

---------------------------------------------------------- ------------------------------

client_result_cache_lag big integer 3000

client_result_cache_size big integer 0

result_cache_max_result integer 5

result_cache_max_size big integer 1M

result_cache_mode string MANUAL

result_cache_remote_expiration integer 0

09:48:09 sys@felix SQL>

上面显示的参数中result_cache_mode用于控制Server result cache的模式,该参数有3个可选设置。

(1) 设置auto:则优化器会自动判断是否将查询结果缓存。

(2) 设置manual:则需要通过查询提示result_cache来告诉优化器是否缓存结果。

(3) 设置force :则尽可能地缓存查询结果(通过提示no_result_cache可以拒绝缓存)

09:52:31 scott@felix SQL>create table felix asselect * from dba_objects;

Table created.

09:53:28 scott@felix SQL>alter systemflush SHARED_POOL;

System altered. 

09:53:42 scott@felix SQL>alter system flushBUFFER_CACHE; 

System altered. 

09:54:06 scott@felix SQL>set autot on;

09:54:25 scott@felix SQL>select count(*) fromfelix; 

COUNT(*)

----------

75613 

Execution Plan

----------------------------------------------------------

Plan hash value: 2587295606 

--------------------------------------------------------------------

| Id |Operation | Name | Rows | Cost (%CPU)| Time |

--------------------------------------------------------------------

| 0 |SELECT STATEMENT | | 1 | 301 (1)| 00:00:04 |

| 1 | SORTAGGREGATE | | 1 | | |

| 2 | TABLE ACCESS FULL| FELIX | 63221 | 301 (1)| 00:00:04 |

--------------------------------------------------------------------

Note

-----

- dynamicsampling used for this statement (level=2)

Statistics

----------------------------------------------------------

70 recursive calls

0 db block gets

1167 consistent gets

1351 physical reads

0 redo size

528 bytes sent via SQL*Net to client

523 bytes received via SQL*Netfrom client

2 SQL*Net roundtrips to/fromclient

5 sorts (memory)

0 sorts (disk)

1 rows processed

09:54:44 scott@felix SQL>

现在再来看看在Server Result Cache下Oracle的行为,首先在result_cache_mode参数设置为MANUAL时:

09:56:02 scott@felix SQL>show parameterresult_cache_mode

NAME TYPE VALUE

------------------------------------ -----------------------------------

result_cache_mode string MANUAL

09:56:50 scott@felix SQL>

需要在SQL语句中手工指定Cache,这需要通过加入一个hints来实现,这个hints是result_cache:

09:56:50 scott@felix SQL>select /* result_cache */ count(*) from felix;

COUNT(*)

----------

75613

执行计划

------------------------------------------------------------ -----------

计划哈希值:2587295606

------------------------------------------------------------ -------------------------------------------------------

| ID |操作|名称 |行|成本(%CPU)|时间|

------------------------------------------------------------ -------------------------------------------------------

| 0 |选择语句| | 1 | 301 (1)| 00:00:04 |

| 1 |结果缓存 | 1hnnwscv2aj3631n497zczt04j | | | |

| 2 |排序聚合| | 1 | | |

| 3 |表访问已满|费利克斯 | 63221 | 301 (1)| 00:00:04 |

------------------------------------------------------------ ------------------------------------------- 

结果缓存信息(通过操作id标识):

------------------------------------------------------------ ------- 

1-列数=1;依赖项=(斯科特.费利克斯);属性=(单行);name=“select /* result_cache */ count(*) from felix”

注意

-----

- 用于此语句的动态采样(级别=2)

统计数据

------------------------------------------------------------ -----------

4 次递归调用

0 db 块获取

1137 一致获取

1077 次物理阅读

0 重做大小

通过 SQL*Net 发送到客户端

528 字节

通过 SQL*Net 从客户端接收到 523 字节

与客户端之间的 2 次 SQL*Net 往返

0 种(记忆)

0 种(磁盘)

已处理 1 行

09:58:49 scott@felix SQL> 

注意到这个执行计划已经和以往的不同,RESULTCACHE以1hnnwscv2aj3631n497zczt04j名称创建。那么在接下来的查询中,这个结果缓存就可以被利用: 

09:58:49 scott@felix SQL>select /* result_cache */ count(*) from felix; 

COUNT(*)

----------

75613 

执行计划

------------------------------------------------------------ -----------

计划哈希值:2587295606 

------------------------------------------------------------ -------------------------------------------------------

| ID |操作|名称 |行|成本(%CPU)|时间|

------------------------------------------------------------ -------------------------------------------------------

| 0 |选择语句| | 1| 301 (1)| 00:00:04 |

| 1 |结果缓存 | 1hnnwscv2aj3631n497zczt04j | | | |

| 2 |排序聚合 | | 1 | | |

| 3 |表访问已满|费利克斯 | 63221 | 301 (1)| 00:00:04 |

------------------------------------------------------------ ------------------------------------------- 

结果缓存信息(通过操作id标识):

------------------------------------------------------------ ------- 

1 - 列数=1;依赖项=(SCOTT.FELIX);属性=(单行); name="select /* result_cache */ count(*) from felix" 

注意

-----

- 用于此语句的动态采样(级别=2)

统计数据

------------------------------------------------------------ -----------

0 次递归调用

0 db 块获取

0 一致获取

0 物理读取

0 重做大小

通过 SQL*Net 发送到客户端

528 字节

通过 SQL*Net 从客户端接收到 523 字节

与客户端之间的 2 次 SQL*Net 往返

0 种(记忆)

0 种(磁盘)

已处理 1 行

10:01:08 scott@felix SQL> 

在这个利用到Result Cache的查询中,一致性获取减少到0,直接访问结果集,不再需要执行SQL查询。这就是Result Cache的具体端点。

在以上测试中,当result_cache_mode设置为MANUAL时,只有使用提示的情况下,Oracle才会利用服务器结果集;而如果将result_cache_mode设置为AUTO,Oracle如果发现缓冲结果集已经存在,现在就自动使用。但是如果缓冲结果集不存在,Oracle并不会自动进行缓冲,只有使用HINT的情况下,Oracle才会将执行的结果集缓存。

可以通过查询v$result_cache_memory查看Cache的使用情况:

10:05:07 scott@felix SQL>select * fromV$RESULT_CACHE_MEMORY where free='NO'; 

ID 块偏移免费 OBJECT_ID 位置

---------- ---------- ---------- ------ -------------- ---------

0 0 0 否 0 0

1 0 1 否 1 0 

10:05:12 scott@felix SQL> 

V$RESULT_CACHE_MEMORY

V$RESULT_CACHE_MEMORY 显示所有内存块及其状态。

 

专栏

数据类型

描述

ID

数字

唯一区块标识符(即区块编号)

数字

块所属的Chunk(ID的高27位)

偏移

数字

块在其块内的偏移量(ID 的低 5 位)

免费

VARCHAR2(3)

指示该块是否空闲(YES)或不空闲(NO)

OBJECT_ID

数字

内存块所属的缓存对象;如果内存块未分配给缓存对象,则为 NULL(FREE = YES)

位置

数字

该块在缓存对象中的位置;如果内存块未分配给缓存对象,则为 NULL(FREE = YES)

 

通过V$RESULT_CACHE_STATISTICS可以查询结果缓存的统计信息: 

10:15:27 scott@felix SQL>select * fromV$RESULT_CACHE_STATISTICS; 

IDNAME 值

------------------------------------------------------------ --- ------------------------------------

1 块大小(字节)1024

2块计数最大1024

3块计数当前 32

4结果大小最大(块)51

5创建计数成功1

6创建计数失败0

7找到计数 1

8失效计数 0

9删除计数无效0

10删除计数有效 0

11哈希链长度1

12查找副本计数 1

已选择 12 行。 

10:15:34 scott@felix SQL> 

V$RESULT_CACHE_OBJECTS 记录了缓存的对象: 

10:20:54 scott@felix SQL>SELECT ID,TYPE,NAME,BLOCK_COUNT,ROW_COUNTFROM V$RESULT_CACHE_OBJECTS; 

IDTYPE 名称 BLOCK_COUNT ROW_COUNT

---------- ------------------------------------- ----------------------- ----------- ----------

0依赖 SCOTT.FELIX 1 0

1Result select /* result_cache */ count(*) from 1 1

菲利克斯

10:21:19 scott@felix SQL> 

V$RESULT_CACHE_OBJECTS 显示所有对象(缓存的结果和依赖项)及其属性。

专栏

数据类型

描述

ID

数字

缓存对象的标识符(也是第一个块的ID)

类型

VARCHAR2(10)

缓存对象的类型:

  • 结果依赖

状态

VARCHAR2(9)

对象的状态:

  • 新 - 结果仍在构建中 已发布 - 结果可供使用 绕过 - 结果将被绕过使用 已过期 - 结果已超过过期时间 无效 - 结果不再可供使用

BUCKET_NO

数字

对象的内部哈希桶

哈希

数字

对象的哈希值

姓名

VARCHAR2(128)

名称(例如 SQL 前缀或 PL/SQL 函数名称)

命名空间

VARCHAR2(5)

命名空间:

  • SQL PLSQL

CREATION_TIMESTAMP

日期

对象创建时间

CREATOR_UID

数字

创建对象的 UID

DEPEND_COUNT

数字

依赖项(TYPE = Result)或依赖项(TYPE = Dependency)的数量

BLOCK_COUNT

数字

缓存对象中的块总数

SCN

数字

构建 SCN(TYPE = 结果)或失效 SCN(TYPE = 依赖项)

COLUMN_COUNT

数字

缓存结果中的列数脚 1

PIN_COUNT

数字

此结果的活动扫描数量Footref 1

SCAN_COUNT

数字

对缓存结果发起的扫描总数Footref 1

ROW_COUNT

数字

缓存结果中的总行数Footref 1

ROW_SIZE_MAX

数字

最大行的大小(以字节为单位)Footref 1

ROW_SIZE_MIN

数字

最小行的大小(以字节为单位)Footref 1

ROW_SIZE_AVG

数字

行的平均大小(以字节为单位)Footref 1

构建时间

数字

构建缓存结果所花费的时间(以百分之一秒为单位)Footref 1

LRU_NUMBER

数字

LRU 列表位置(值越小,最近使用过)Footref 1

OBJECT_NO

数字

依赖对象的字典对象编号Foot 2

无效

数字

对象使其依赖项无效的次数Footref 2

SPACE_OVERHEAD

数字

结果的开销(以字节为单位)Footref 1

SPACE_UNUSED

数字

结果的未使用空间(以字节为单位)Footref 1

CACHE_ID

VARCHAR2(93)

结果的 CacheId(如果是依赖项,则为对象名称)

CACHE_KEY

VARCHAR2(93)

结果的CacheKey(如果是依赖项,则为对象名称)

DB_LINK脚 3

VARCHAR2(3)

可能的值:

  • YES:如果结果缓存对象引用远程数据库对象 NO:如果结果缓存对象未引用远程数据库对象

校验和Footref 3

数字

结果对象的校验和。校验和是针对结果缓存对象中减去对象标头的所有块计算的。

脚注 1 这些列仅对 TYPE = Result 有效;否则,它们为 NULL。

脚注 2 这些列仅对 TYPE = Dependency 有效;否则,它们为 NULL。

脚注 3 此专栏从 Oracle Database11g 第 2 版 (11.2.0.4) 开始提供

表 7-6 与服务器和客户端结果缓存相关的视图和表

标题> 表>

引入了一个新的系统包,DBMS_RESULT_CACHE可以用于执行关于结果缓存的管理: 

10:21:19scott@felix SQL>设置服务器输出

10:25:30 scott@felix SQL>execdbms_result_cache.memory_report

结果缓存内存报告

[参数]

块大小 = 1K 字节

最大缓存大小 = 1M 字节(1K 块)

最大结果大小 = 51K 字节(51 个块)

[记忆]

总内存 = 165032 字节 [SharedPool 的 0.096%]

...固定内存 = 5352 字节 [共享池的 0.003%]

...动态内存 = 159680 字节 [共享池的 0.093%]

......开销 = 126912 字节

......缓存内存 = 32K 字节(32 个块)

......未使用的内存= 30块

...........已用内存 = 2 块

............依赖项 = 1 个块(1 个计数)

........................结果 = 1 个区块

................... SQL = 1 块(1 个计数)

PL/SQL 过程已成功完成。 

10:25:49 scott@felix SQL>

1.2.2 Shared Pool 的设置说明

Shared Pool的大小可以通过初始化参数shared_pool_size设置。在Oracle 10g之前很多共享池的设置上存在不同的声音,鉴于很多人建议把Shared Pool设置得稍大,以充分CacheCode和避免ORA -04031错误的出现;另外还有很多人建议不能把Shared Pool设置得过大,因为过大可能会带来管理上的额外负担,从而会影响数据库的性能。

在下面的测试中占用了Shared Pool的转储,所以首先需要了解一下相关的命令。可以通过如下命令转储Shared Pool共享内存的内容:

注意alter session setevents 'immediate trace name heapdump level 2'是一条内部命令,指定Oracle把Shared Pool的内存结构在Level 2级转储出来

Get_trc_scripts.sql

选择一个.VALUE || b.符号|| c.instance_name ||'_ora_' || d.spid ||

'.trc'trace_file_name

FROM(SELECT VALUE FROM v$parameter WHERE NAME = 'user_dump_dest') a,

(SELECT SUBSTR(VALUE, -6, 1) 符号

FROM v$参数

WHERE NAME = 'user_dump_dest') b,

(从 v$instance 中选择实例名称) c,

(选择 spid

来自 v$session s、v$process p、v$mystat m

其中 s.paddr = p.addr

AND s.SID = m.SID

AND m.statistic# = 0) d; 

TRACE_FILE_NAME

------------------------------------------------------------ ----------------------

/u01/app/oracle/diag/rdbms/felix/felix/trace/felix_ora_2751.trc 

10:36:03 scott@felix SQL> 

Shared Pool通过Free Lists管理空闲内存块(Chunk),空闲的内存块(Chunk)按大小不一样被划分到不同的部分(Bucket)进行管理;

可以通过下图对共享池的空闲列表管理进行说明

不同桶管理的内存块的大小范围如下图(大小显示的是下边界):

[oracle@felix~]$ cat /u01/app/oracle/diag/rdbms/felix/felix/trace/felix_ora_2751.trc | grepbucket

预留桶 0 大小=32

预留桶 1 个尺寸=4400

预留桶2尺寸=8216

预留桶3号=8696

预留桶 4 尺寸=8704

预留桶5号=8712

预留桶6号=8720

预留桶7号=9368

预留桶8号=9376

预留桶 9 尺寸=12352

预留桶 10 尺寸=12360

预留桶 11 尺寸=16408

预留桶 12 尺寸=32792

预留桶13尺寸=65560

预留桶 14 尺寸=1990644

块 0788db800 sz= 968 个可释放的“vproblem_bucket”

块 0788dbde8 sz= 872 个可释放的“vproblem_bucket”

块 0788dc370 sz= 872 个可释放的“vproblem_bucket”

预留桶 0 大小=32

预留桶 1 个尺寸=4400

预留桶2尺寸=8216

预留桶3号=8696

预留桶 4 尺寸=8704

预留桶5号=8712

预留桶6号=8720

预留桶7号=9368

预留桶8号=9376

预留桶 9 尺寸=12352

预留桶 10 尺寸=12360

预留桶 11 尺寸=16408

预留桶 12 尺寸=32792

预留桶13尺寸=65560

预留桶 14 尺寸=1990644

预留桶 0 大小=32

预留桶 1 个尺寸=4400

预留桶2尺寸=8216

预留桶3号=8696

预留桶 4 尺寸=8704

预留桶5号=8712

预留桶6号=8720

预留桶7号=9368

预留桶8号=9376

预留桶 9 尺寸=12352

预留桶 10 尺寸=12360

预留桶 11 尺寸=16408

预留桶 12 尺寸=32792

预留桶13尺寸=65560

预留桶 14 尺寸=1990644

预留桶 0 大小=32

预留桶 1 个尺寸=4400

预留桶2尺寸=8216

预留桶3号=8696

预留桶 4 尺寸=8704

预留桶5号=8712

预留桶6号=8720

预留桶7号=9368

预留桶8号=9376

预留桶 9 尺寸=12352

预留桶 10 尺寸=12360

预留桶 11 尺寸=16408

预留桶 12 尺寸=32792

预留桶13尺寸=65560

预留桶 14 尺寸=1990644

[oracle@felix ~]$

 

最初,数据库启动以后,共享池大部分是连续内存块。但是当空间分配使用以后,内存块开始被分割,碎片开始出现,Bucket列表开始变长。

Oracle请求Shared Pool空间时,首先进入相应的Bucket进行查找。如果找不到,则转向下一个非空的Bucket,获取第一个Chunk。分割这个Chunk,剩下部分会进入相应的的桶,进一步增加碎片

最终的结果是,由于不断分割,每个Bucket上的内存块会越来越多,越来越碎。通常Bucket 0的问题会非常明显,在这个测试数据库上, Bucket 0上的碎片已经达到9030个,而shared_pool_size设置了150MB。

通常如果每个Bucket上的Chunk多于2000个,就被认为是Shared Pool垃圾过多。Shared Pool的垃圾过多,是Shared Pool产生性能问题的主要原因。

垃圾过多会导致搜索Free Lists的时间过长,而我们知道,Free Lists的管理和搜索都需要获取并持有一个非常重要的Latch,那就是Shared Pool Latch。Latch是Oracle数据库内部提供了一种低级锁,通过串行机制保护共享内存不被并发更新/修改所损坏。锁存器的持有通常都非常短(通常是微秒级),但是对于一个单一的数据库,这个串行机制往往会成为极大的性能瓶颈。

如果Free Lists表过长,搜索这个Free Lists的时间就会变长,从而可能导致Shared Pool Latch被长时间持有,在一个间歇的系统中,这会引起严重的Shared PoolLatch的竞争。在Oracle 9i之前,这个重要的Shared Pool Latch只有一个,所以长时间持有会导致严重的性能问题。

1.2.3 Oracle 9i 子缓冲池的增强

从Oracle 9i开始,Shared Pool可以被分割为多个子缓冲池(SubPool)进行管理,每个SubPool可以被分成一个Mini Shared Pool,拥有自己独立的Free List、内部存结构以及LRU List。同时Oracle?提供多个Latch对各个子缓冲池进行管理,从而避免单个Latch的竞争(Shared Pool Reserve Area同样进行分割管理)。SubPool最多可以有7个,Shared Pool Latch也从原来的一个增加到现在的7个。如果系统有4个或4个以上的CPU,并且SHARED_POOL_SIZE大于250MB,Oracle可以把Shared Pool分割为多个子缓冲池(SubPool)进行管理,在Oracle 9i中,每个SubPool至少为128MB。

Oracle 9i中多个子缓冲池的结构示意图如图所示:

以下查询显示的是管理SubPool而新增的子Latch: 

选择地址、名称、获取、未命中、spin_gets

来自v$latch_children

其中 name = '共享池'; 

地址名称未命中 SPIN_GETS

------------------------------------------------------------ --------- ---------- ---------- ----------

00000000601072A0 共享池 24 0 0

0000000060107200 共享池 24 0 0

0000000060107160 共享池 24 0 0

00000000601070C0 共享池 24 0 0

0000000060107020 共享池 24 0 0

0000000060106F80 共享池 24 0 0

0000000060106EE0 共享池 325942 10 1 

已选择 7 行。 

11:02:08 scott@felix SQL> 

但是需要注意的是,虽然多缓冲池技术使Oracle可以管理更大的共享池,但是SubPool的划分可能也会导致各分区之间的协调问题,甚至可能因为内存分散而出现ORA-04031错误。最常见的问题是某个子缓冲池(SubPool)可能出现过度使用,当新的进程仍然被分配到这个SubPool时,可能会导致内存请求失败(而此时其他SubPool可能还有很多内存空间)。

select KSMCHIDX "SubPool",

'sgaheap(' || KSMCHIDX || ',0)' sga_heap,

ksmchcom ChunkComment,

decode(round(ksmchsiz / 1000),

0,

'0-1K',

1,

'1-2K',

2,

'2-3K',

3,

'3-4K',

4,

'4-5K',

5,

'5-6k',

6,

'6-7k',

7,

'7-8k',

8,

'8-9k',

9,

'9-10k',

'> 10K') "size",

count(*),

ksmchcls Status,

sum(ksmchsiz) Bytes

fromx$ksmsp

whereKSMCHCOM = 'free memory'

group byksmchidx,

ksmchcls,

'sga heap(' || KSMCHIDX || ',0)',

ksmchcom,

ksmchcls,

decode(round(ksmchsiz / 1000),

0,

'0-1K',

1,

'1-2K',

2,

'2-3K',

3,

'3-4K',

4,

'4-5K',

5,

'5-6k',

6,

'6-7k',

7,

'7-8k',

8,

'8-9k',

9,

'9-10k',

'> 10K');

因为子缓冲池存在的种种问题,从Oracle 10g开始,Oracle允许内存请求在不同SubPool之间进行切换(Switch),从而?高了请求成功的可能(但是显然切换不可能是无限制的,所以问题仍然可能存在)。

8个子池都被使用,其Latch使用情况如下:

select child#, gets

fromv$latch_children

where name= 'shared pool'

order bychild#;

CHILD# GETS

---------- ----------

1 343101

2 24

3 24

4 24

5 24

6 24

7 24

7 rows selected. 

11:42:25 sys@felix SQL>

1.2.4 Oracle 10g 共享池管理的增强

子缓冲池的分配的算法很简单:

(1)每个子缓冲池必须满足一定的内存约束;

(2)每4颗CPU可以分配一个子缓冲池,最多7个。 

在Oracle 9i中,每个SubPool至少128MB,在Oracle10g中,每个子缓冲池至少为256MB。如前所述,SubPool的数量可以通过_kghdsidx_count参数来控制,但是没有参数可以显示地控制SubPool的大小。

不管Oracle 9i中的128MB以及Oracle10g中的256MB,某些情况下,可能需要增加SubPool的大小。可以通过控制Shared Pool大小以及SubPool的数量来改变SubPool的大小。一些Bug以及内部测试表明500MB的SubPool可能会带来更好的性能,所以从Oracle 11g开始,每个SubPool至少为512MB。

除大小控制之外,在Oracle 10g中,Oracle仍然对共享池的管理做出了进一步改进,那就是对单个子缓冲池进行进一步的细分。现在缺省地,Oracle 10g会将单个缓冲池分割为会4个子分区进行管理(这可能是因为通常4颗CPU才分配一个SubPool),使用类似如上的方法在Oracle 10gR2中进行测试:

分析得到的日志,当仅有一个子缓冲时,SharedPool被划分为sga heap(1,0)~sgaheap(1,3)共4个子分区:

[root@felix~]# cat /u01/app/oracle/diag/rdbms/felix/felix/trace/felix_ora_4324.trc | grep"sga heap"

HEAP DUMP heap name="sga heap" desc=0x60001190

HEAP DUMP heap name="sga heap(1,0)" desc=0x60053f70

HEAP DUMP heap name="sga heap(1,1)" desc=0x600557c8

HEAP DUMP heap name="sga heap(1,2)" desc=0x60057020

HEAP DUMP heap name="sga heap(1,3)" desc=0x60058878

[root@felix ~]#

当使用两个子缓冲时,Shared Pool则被划分为8个子分区进行管理; 

Oracle 10g中多缓冲池结构示意图如下图所示


通过一个内部表X$KGHLU([K]ernel [G]eneric memory [H]eap manager State of [L]R[U] OfUnpinned Recreatable chunks)可以查询这些子缓冲池的分配: 

11:59:29 sys@felix SQL>selectaddr,indx,kghluidx,kghludur,kghluops,kghlurcr from x$kghlu; 

ADDR INDX KGHLUIDX KGHLUDUR KGHLUOPS KGHLURCR

---------------- ---------- ---------- -------------------- ----------

00007FA372851098 0 1 0 119290 4425 

12:03:45 sys@felix SQL> 

通过这一系列的算法改进,Oracle中Shared Pool管理得以不断增强,较好的解决了大Shared Pool的性能问题;Oracle 8i中,过大Shared Pool设置可能带来的栓锁争用等性能问题在某种程度上得以解决。从Oracle10g开始,Oracle开始?供自动共享内存管理,使用该特性,用户可以不必显示设置共享内存参数,Oracle会自动进行分配和调整,虽然Oracle给我们提供了极大的便利,但是了解自动化后面的原理对于理解Oracle的运行机制仍然是十分重要的。

View/Table

Description

V$RESULT_CACHE_STATISTICS

Lists various server result cache settings and memory usage statistics.

V$RESULT_CACHE_MEMORY

Lists all the memory blocks in the server result cache and their corresponding statistics.

V$RESULT_CACHE_OBJECTS

Lists all the objects whose results are in the server result cache along with their attributes.

V$RESULT_CACHE_DEPENDENCY

Lists the dependency details between the results in the server cache and dependencies among these results.

CLIENT_RESULT_CACHE_STATS$

Stores cache settings and memory usage statistics for the client result caches obtained from the OCI client processes. This statistics table has entries for each client process that is using result caching. After the client processes terminate, the database removes their entries from this table. The client table lists information similar to V$RESULT_CACHE_STATISTICS.

See Also: Oracle Database Reference for details about CLIENT_RESULT_CACHE_STATS$

DBA_TABLES, USER_TABLES, ALL_TABLES

Includes a RESULT_CACHE column that shows the result cache mode annotation for the table. If the table has not been annotated, then this column shows DEFAULT. This column applies to both server and client result caching.

视图/表格
描述
V$RESULT_CACHE_STATISTICS 列出各种服务器结果缓存设置和内存使用统计信息。
V$RESULT_CACHE_MEMORY 列出服务器结果缓存中的所有内存块及其对应的统计信息。
V$RESULT_CACHE_OBJECTS 列出结果位于服务器结果缓存中的所有对象及其属性。
V$RESULT_CACHE_DEPENDENCY 列出服务器缓存中的结果之间的依赖关系详细信息以及这些结果之间的依赖关系。
CLIENT_RESULT_CACHE_STATS$ 存储从 OCI 客户端进程获取的客户端结果缓存的缓存设置和内存使用统计信息。该统计表包含每个使用结果缓存的客户端进程的条目。客户端进程终止后,数据库会从此表中删除它们的条目。客户端表列出了类似V$RESULT_CACHE_STATISTICS的信息。 另请参阅: Oracle 数据库参考,了解有关 CLIENT_RESULT_CACHE_STATS$ 的详细信息
DBA_TABLES、USER_TABLES、ALL_TABLES 包括一个 RESULT_CACHE 列,显示表的结果缓存模式注释。如果表尚未注释,则此列显示 DEFAULT。此列适用于服务器和客户端结果缓存。
声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn