测量共享池的性能
· 共享池的性能主要用库缓存命中率和数据字典缓存命中率来测量,前者更重要,Oracle建议在未调整好库缓存之前,不必费力去调整数据字典缓存。
测量库缓存的性能
· 库缓存的性能指标来自V$LIBRARYCACHE视图,这个视图的主要字段描述如下:
字段名 描述 可接受值(OLTP)
NAMESPACE 主要的类型有SQL AREA (SQL语句), TABLE/PROCEDURE (存储过程或函数), BODY (包体), TRIGGER (触发器)
GETS 解析次数
GETHITS 解析时发现语句的解析版本已存在于库缓存中(解析命中)的次数
GETHITRATIO 解析命中率 大于90%
PINS 执行次数
PINHITS 执行命中次数
PINHITRATIO 执行命中率 大于90%
RELOADS 重新解析的次数,重新解析的原因是已缓存的解析版本老化或失效 sum(reloads)/sum(pins) < 1%
INVALIDATIONS 语句缓存失效的次数,失效的原因是依赖对象被修改删除或者编译
· STATSPACK中存放关于库缓存性能的数据有两个地方:
?nbsp; Instance Efficiency Percentages (Target 100%)(实例命中率) – Library Hit %;
?nbsp; Library Cache Activity for DB(库缓存活动)。
测量数据字典缓存的性能
· 数据字典缓存性能指标来自V$ROWCACHE视图,用下面的查询来获得命中率:
select 1 – (sum(getmisses) / sum(gets)) from v$rowcache;可以接受的命中率是85%以上;
· STATSPACK中关于数据字典缓存性能的数据存放在Dictionary Cache Stats for DB(数据字典缓存统计)。
第四章 调整共享池 3.改进共享池的性能
改进共享池的性能
改进共享池的性能就是提高库缓存和数据字典缓存的命中率,有以下一些方法:
增大共享池
· 增大共享池能减慢库缓存和数据字典缓存被LRU算法移出的速度,从而提高命中率;
· 库缓存命中率和数据字典缓存命中率通常都趋向于一致,极少出现一高一低的情形;
· 共享池的大小由初始化参数SHARED_POOL_SIZE来确定;
· 已使用库缓存的大小可以通过sum(V$DB_OBJECT_CACHE.SHARABLE_MEM)(非SQL对象)和 sum(V$SQLAREA.SHARABLE_MEM)(SQL语句) 来查询;
· 可以用ALTER SYSTEM SET SHARED_POOL_SIZE = XX; 来动态更改共享池的大小,但需保证更改后SGA的大小不大于SGA_MAX_SIZE,否则会现ORA-04033的错误;
· 也可以通过关机更改初始参数SHARED_POOL_SIZE再重启来手工更改共享池的大小,这种方法适于同时改大SGA_MAX_SIZE这个参数;
· 无统计数据时,可以按照下面的策略来为ORACLE服务器分配内存:
?nbsp; 操作系统(NT需要的较UNIX多),ORACLE后台进程,服务器进程,其它非ORACLE进程共需内存= 服务器总内存 * 45%(1G以下时) or 25~40%(1G以上时);
?nbsp; TSGA(SGA总内存) = 服务器总内存 * 55%(1G以下时) or 60~75%(1G以上时);
?nbsp; TSGAI(单个实例的SGA内存) = TSGA / 服务器上的实例数;
?nbsp; 共享池 = TSGAI * 45%;
?nbsp; 数据缓存 = TSGAI * 45%;
?nbsp; 日志缓存 = TSGAI * 10% (10%的日志缓存通常都偏大,可待有统计数据后视情形将多出的部分分给共享池,数据缓存或者大池);
?nbsp; 若需配置大池和JAVA池时,从本实例SGA总内存中分配。
为大的PL/SQL语句留空间;
· 执行大的PL/SQL程序时,为了获得足够的缓存空间,LRU算法会移出许多已解析的语句,尔后这些刚被移出的语句可能又要重新装入,这样就降低的库缓存的命中率,为了避免这样的情形,可以设置共享池保留区给大的PL/SQL对象使用;
· 参数SHARED_POOL_RESERVED_SIZE用来指定共享池保留区的大小,最大可指定到共享池的一半,默认值是共享池的5%,ORACLE建议从共享池的10%开始调整;
· 可以从V$DB_OBJECT_CACHE查到目前缓存对象及其使用空间(OWNER, NAME, SHARABLE_MEM);
· 可以用V$SHARED_POOL_RESERVED视图来监控保留区的使用情况以决定正确的保留区大小:
?nbsp; REQUESTS 从保留区中请求空间的次数;
?nbsp; REQUEST_MISSES 保留区无空间可用而需要从非保留区清洗对象的请求次数;这个值为零或者一直很稳定表示保留区空间设置偏大;
?nbsp; FREE_SPACE 保留区未用的空间;这个空间大于保留区的一半时表示保留区空间设置偏大;
?nbsp; REQUEST_FAILURES 请求无法满足,出现ORA-04031错误的次数; 这个值非零或者稳定增加时表示保留区太小;
?nbsp; 隐含参数_shared_pool_reserve_min_alloc(4400)确定请求保留区的起始大小;
?nbsp; 调整保留区的目标是使REQUEST_MISSES, REQUEST_FAILURES接近零。
· 可以用DBMS_SHARED_POOL.ABORT_REQUEST_THRESHOLD这个包过程设置一个阀值,大于这个值的库缓存请求将会失败。
Keep PL/SQL
· 将重用率高的PL/SQL代码KEEP在库缓存中可以提高命中率,这个过程又称Pinning,由DBMS_SHARED_POOL.KEEP过程来完成,这些对象存放在共享池保留区中;
· 清洗共享池语句(ALTER SYSTEM FLUSH SHARED_POOL;)并不会清洗Pinned对象,但是系统重启后,这些对象将不再是Pinned。
· Keep相关:
?nbsp; DBMS_SHARED_POOL这个包并没有在运行catproc.sql时安装,需运行一次dbmspool.sql这个脚本;
?nbsp; 可以用这个包中的KEEP, UNKEEP来pin 和unpin存储对象;
?nbsp; 可从V$DB_OBJECT_CACHE.KEEP这个栏位得知哪些对象已被Pinned。
· 要确定哪些对象适于KEEP,可以激活审计功能来查看是哪些对象被频繁地调用,要KEEP匿名的PL/SQL程序比较麻烦,建议将经常使用且长度超过500个字符的匿名块写成过程和包再进行KEEP;
· 因为重启后所有的KEEP都将失效,所以将KEEP的动作放在系统触发器中(AFTER STARTUP ON DATABASE)是较合适的。
代码重用;
· 确定是否需要对语句进行(硬)解析时,是先比较语句的哈希值,下面的两种方法有助于获得相同的哈希值,从而可以实现重用代码,提高命中率:
?nbsp; 开发组的所有成员都使用相同的编码规范(包括大小写,空格,换行等);
?nbsp; 使用绑定变量(提高命中率的同时可能会产生不够好的执行计划,因为优化器不知道变量的确定值,在有栏位的柱状图统计数据时也不能够利用)。
调整相关初始化参数。
OPEN_CURSORS
· 这个参数指定每个用户会话能打开的游标个数;
· 增大这个值可以减少重新解析会话曾打开的语句的机会,提高命中率,但需要更大的共享池空间。
CURSOR_SPACE_FOR_TIME
· 这个参数设为真时,只有当所有引用共享SQL的游标都关闭后,LRU才有可能移出这个SQL所占的缓存空间来重用,默认值是FALSE;
· 只有在共享池足够大的情况下才能考虑设为真,设为真时可以减少重解析,提高命中率,加快游标的执行(空间换时间)。
SESSION_CACHED_CURSORS
· 这个参数指定会话能够缓存游标的个数,默认值是零;
· 如果会话反复执行某些语句,设置该值大于零能提高游标的执行速度,这些缓存也是用LRU算法来管理的。
CURSOR_SHARING
· 这个参数决定什么样的SQL语句能够共享游标,有三个取值:FORCE, SIMILAR, EXACT;
?nbsp; FORCE 两个语句的差异只在字面值,这些差异不会改变语句的含义时可共享游标;
?nbsp; SIMILAR两个语句的差异只在字面值,这些差异不会改变语句的含义和执行计划时可共享游标(这个值是在9i 中引入,如果有差异的栏位上有柱状图统计,这时执行计划会改变,不能共享游标,行为同于EXACT,如果差异栏位上没有柱状图统计,执行计划相同,这时的行为同于FORCE);
?nbsp; EXACT 两个语句必须精确匹配才能共享游标,这是默认值。
第五章 调整数据缓存 1.理解数据缓存
理解数据缓存
· 数据缓存是SGA的一部分,用于存放用户最近存取过的段的数据块的副本,这些段可能是数据段,索引段,簇段,LOB段,LOB索引段,回滚段,临时段,数据缓存单元的大小与数据库块大小一致。
· 数据缓存用下面的方法进行管理:
LRU列表
· 在Oracle执行SQL语句的过程中,相关的段数据要复制到SGA的数据缓存中来,这个操作由用户的服务器进程来执行;
· 与共享池类似,数据缓存也是由LRU算法来管理的,当数据缓存的缓存块被填满而又有新的缓存块请求时,LRU将最近最少使用的缓存块老化出去,而保留最近经常使用的缓存块,当一个用户发现要读取的数据块已在之前由其它用户读入时,就可以节约很多时间,因为从内存中读取比从磁盘中读取要快上数千倍;
· LRU算法管理一个LRU列表,这个列表类似于一个输送带,服务器进程将刚刚存取过的数据块放在输送带的开始端,随着更多的块被读入,先前读入的块向输送带末端移动,如果在到达末端之前某个块被再一次存取,则这个块又被移到开始端,否则就会从输送带末端跌落(缓存块被老化);
· LRU对全表扫描时读入缓存块的管理与上面的有些不同,这些块一读入就被放在LRU列表的末端,这样可以避免对大表全表扫描时把数据缓存中的所有缓存块都清洗出去;
· LRU算法管理下的缓存块有四种状态:
?nbsp; Free 自数据库启动以来尚未被使用过的缓存块;
?nbsp; Pinned 正在被服务器进程使用的缓存块;
?nbsp; Clean 曾被使用过且可立即被重用的缓存块,读入后未经修改或者最近一次修改已被写回磁盘,缓存版本与文件数据块一致;
?nbsp; Dirty 曾被使用过且不能立即被重用的缓存块,读入后作过修改且最近一次修改未被写回磁盘,缓存版本与文件数据块不一致;
· 管理脏块时会用到一个脏块列表(Dirty List,又名写列表),这个列表被检查点队列使用,用于跟踪所有的脏块,以第一次修改时间排序,脏块由DBW0进程写回磁盘。
用户服务器进程
· 当需要读取某个数据块时,服务器进程先到数据缓存中查看该块是否已存在,若没有找到,就需要将数据块从数据文件读到数据缓存中来,这首先要在数据缓存中找到一个可用的缓存块来容纳数据块的副本,这个过程中服务器进程可能要和LRU列表以及脏列表打交道:
?nbsp; 在LRU列表上查找可用块的时候,服务器进程将查到的脏块从LRU列表移到脏列表;
?nbsp; 随着脏块的加入,脏列表不断变长,当长度超过某个预定义的长度时,触发DBW0将脏列表上的脏块写回磁盘;
?nbsp; 如果服务器进程在LRU列表查找很多的块(超过某个阀值)都没能找到可用的块时,触发DBW0进程,将脏块直接从LRU列表写回磁盘。
· 如果服务器进程发现要找的块已在数据缓存中,但块的版本要晚于一致性读需要的版本时(版本更早时可直接使用),服务器进程在数据缓存中创建一个新块利用回滚段数据回滚到需要的版本(如果是在序列化事务中,且造成更晚版本的已提交的修改不是由当前事务造成的话,则报错)。
数据库写入进程(DBW0)
· DBW0进程负责将数据缓存中的脏块写回磁盘,这个操作在下面的情形下发生:
?nbsp; 服务器进程不断地将脏块从LRU列表移到脏列表,当脏列表的长度达到阀值时,DBW0将脏列表上的脏块写回磁盘;
?nbsp; 服务器进程在LRU列表上检查太多的块都没能找到一个可用块的时候,DBW0直接从LRU列上将脏块写回磁盘;
?nbsp; DBW0进程每三秒被激活一次,将LRU列表上的脏块移到脏列表,若脏列表长度达到阀值时,从脏列表上将脏块写回磁盘;
?nbsp; 检查点发生时,DBW0将脏块从LRU列表移到脏列表,再从脏列表写脏块回磁盘;
?nbsp; 数据库关闭时(不包括Shutdown Abort),DBW0将所有脏块写回磁盘;
?nbsp; 表空间热备前,DBW0将属于这个表空间的所有脏块从LRU列表移到脏列表,然后从脏列表将脏块写回磁盘;
?nbsp; 表空间离线时(Normal,Temporary),DBW0将属于这个表空间的所有脏块从LRU移到脏列表,然后从脏列表将脏块写回磁盘;
?nbsp; 删除段时,DBW0先将这个段的脏块写回磁盘。
阅读(323) | 评论(0) | 转发(0) |