暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SGA的性能调整和优化思路

DBA小记 2020-10-27
1679

SGA的性能调整和优化思路


一、SGA组成

Buffer Cache:主要缓存数据块

Shared Pool:缓存Cursor相关的信息和数据字典

Log Buffer:缓存重做日志条目

提示:Log Buffer不能实现在线动态调整

SGA的一些重要属性

计算性内存。在Unix/Linux系统中,可以通过ipcs观察共享内存

数据库实例的一部分,正常访问表数据的通道


GRANULE

GRANULE是一块真正意义上连续的内存块。是组成SGA的最小原子内存单位(SGA大小能被整除),分为三种状态:

ØFree

ØInitialized

ØAllocated

注意:SGA动态内存管理(ASMM)时,内存之间的移动是以GRANULE为单位的。


获得GRANULE大小的方法:

Ø通过查看隐含参数_ksmg_granule_size获得

Ø通过查询V$SGAINFO获得

GRANULE的大小与SGA大小和数据库版本有关:


二、详解BUFFER CACHE


Buffer Cache的作用

数据库存放在磁盘中

作为数据库的缓存

可以缓存不同大小的数据块

并发性访问受Latch保护

提示:多重缓存不仅带来浪费内存,而且会带来额外的开销,如内核调用


Buffer Cache的使用进程

前台进程:从磁盘中读block至buffer cache中

DBWR进程:从buffer cache写block至磁盘中

提示:前台进程和DBWR进程可以有多个,所以Buffer Cache中需要有latch来保护并发性访问


BUFFER CACHE的命中率

从BUFFER CACHE中读取数据块一般需耗时100ns

从磁盘读取数据块一般需耗时10ms左右(假设缓存没有命中)

问题:Buffer Cache的命中率越高越好?

提示:BUFFER CACHE的命中率并不是越高越好,避免无效的数据块读取才是数据库优化之根本

BUFFER CACHE的命中率高,并不意味着数据库性能良好。

Ø执行计划出错时,逻辑读高,但效率低下

Ø“热”块争用时,逻辑读低,但效率低下



Buffer Cache种类

Default buffer cache:数据块的默认缓冲池,与db_block_size参数有关

Keep buffer cache:缓存热块

Recycle buffer cache:缓存冷块

提示:BUFFER CACHE中没有内存碎片这一说法

BUFFER CACHE的内部结构

BUFFER HEADER指的数据块的缓冲块头,BUFFER HEADER的地址位指向真正的数据块缓冲区。

根据该数据块的DBA/CLASS值进行类HASH运算,然后根据计算出的HASH值挂载到某一个HASH BUCKET中。

不同的数据块经过HASH运算之后可能挂载到同一个HASH BUCKET中。

Oracle将同一个HASH BUCKET的不同数据块用一条HASH CHAIN串联起来

为了防止HASH CHAIN受到进程并发性访问的破坏,Oracle设计了专门的CACHE BUFFERS CHAINS LATCH(以下简称:CBC LATCH)用于保护HASH CHAIN


BUFFER HEADER

控制结构大小占188个字节(Oracle 9i)

查看使用过的BUFFER HEADER的方法如下:

Ø查询X$BH(Buffer Headers)

Ø使用命令DUMP BUFFER CACHE

记住字节大小意义不大,除非是做一些研究性工作。


HASH BUCKET

挂载具有相同HASH值的数据块

默认数量为DB_BLOCK_BUFFERS x 2,查看隐含参数_db_block_hash_buckets获取具体的数量

增加HASH BUCKET的方法:

Ø调整BUFFER CACHE的大小

Ø调整隐含参数_db_block_hash_buckets


HASH CHAIN

串联具有相同HASH值的数据块

Ø会话通过计算数据块(RDBA,CLASS)的HASH值就可以快速定位数据块

Ø同一个数据块的CR块都具有相同的DBA值(CR块数量由隐含参数_db_block_max_cr_dba 控制)

热链

热链指的是高频访问的HASH CHAIN

问题:“热”链如何打破?

使用Hash表或更大的pctfree等技术分散数据块


LATCH:CACHE BUFFERS CHAINS

多进程并发访问时保护HASH CHAIN结构

一个CBC LATCH保护着多条HASH CHAIN

v$session_wait.P1和P1RAW值表示CBC LATCH的地址(属于哪一条hash chain)

服务器进程需要获得CBC LATCH情况:

Ø服务进程扫描HASH CHAIN中的数据块时

Ø服务进程将数据块挂载(PIN)到HASH CHAIN时

通过以下方法可以查询CBC LATCH数量:

Ø查看隐含参数_db_block_hash_latches

Ø查询v$latch_children视图

发生LATCH:CACHE BUFFERS CHAINS等待事件主要有以下几个原因:

Ø低效的SQL。多个并发进程同时大范围扫描表和索引

Ølatch数量不足

ØHash chain 过长

ØHot block。多个并发进程同时读取同一个数据块


LRU相关列

LRU列

LRU-W列

LRU-XO列

LRU-RO列


LRU列

LRU列,又叫替换列。分为主列和辅助列:

Ø主列:已使用的(pinned/ unpinned dirty)数据块缓冲区列

Ø辅助列:空闲的数据块缓冲区列(系统启动之初)


LRU-W列

LRU-W列,又叫写入列(LRU-Write list),脏数据列。分为主列和辅助列:

Ø主列:已修改的数据块缓冲区列

Ø辅助列:当前正等待或正通过DBWR进程写的数据块缓冲区列

服务器进程在检索空闲缓冲区时,首先会检索LRU列的辅助列,当辅助列没有剩余缓冲区时,才会检索LRU主列中的COLD区域

DBWR进程扫描LRU主列脏块,然后将其移动(指针的变化)至LRU-W主列,DBWR进程写脏块时,会将脏块移动至LRU-W辅助列

数据块的buffer header只能挂载在LRU列或者LRU-W列的其中一个列


LRU-XO/XR列

LRU-XO列:Reuse object list;

Ødrop/truncate table等操作

LRU-XR列:Reuse range list; buffers to be written for reuse block range

Ø表空间begin backup/read only等操作

分为主列和辅助列


触发DBWR写脏块条件      

Make free requests           

Checkpoints                  

Ping writes(Oracle 8i OPS)                  

Cleanout of cold dirty buffers


TOUCH COUNT

dump buffer cache

查询x$bh

使用TCH(访问计数器,隐含参数_db_aging_hot_criteria,默认为2 )记录某个buffer被访问的次数。

分为HOT和COLD区域(_db_percent_hot_default,默认50%)

前台进程扫描LRU LIST深度由隐含参数_db_block_max_scan_pct来调整

TCH算法如下:

3秒内(_db_aging_touch_time),如果数据块再次被访问,则TCH不增长

TCH增长不需要LATCH保护,所以可能会出现增长丢失情况


CACHE BUFFERS LRU CHAIN LATCH

主要用于保护进程并发访问LRU LIST

通过以下方法获取当前系统中CACHE BUFFERS LRU CHAIN LATCH的数量:

Ø查询隐含参数_db_block_lru_latches

Ø查询V$LATCH_CHILDREN

不同的缓冲池使用独立的LRU LATCH

和DBWR的数量有关

Ø DBWR数小于4,则创建4*CPU_COUNT

Ø DBWR数大于4,则创建DB_WRITER_PROCESSES*CPU_COUNT

需要获得LRU LATCH的情况如下:

Ø服务进程扫描LRU列( round-robin 方式)获取FREE  BUFFER,即数据块进入BUFFER CACHE之前

ØDBWR进程写脏数据块之前扫描LRU列和LRU-W列

ØDBWR进程将FREE BUFFER 移动至LRU辅助列之前

当许多进程(服务进程和DBWR进程)同时检索LRU列或者LRU-W列时(则容易出现LATCH: CACHE BUFFERS LRU CHAIN等待事件。低效的SQL是主因,大量数据块涌入buffer cache)

LRU LATCH争用往往伴随着大量的 物理I/O

不要简单地通过调整隐含参数_db_block_lru_latches来解决LATCH: CACHE BUFFERS LRU CHAIN等待事件

LRU列和LRU-W列的集合称之为Working Set

每个Working Set拥有独立的LRU LATCH

1个DBWR进程管理1个或者多个Working Sets

不同的Buffer Cache拥有不同的Working Sets


HASH列和LRU列区别

HASH列的作用为了定位数据块

LRU列的作用为了分配缓存(服务进程的工作)和换出缓存(DBWR进程的工作)BLOCK

CBC LATCH和LRU LATCH之间的区别:

Ø多个会话并发访问相同的表或者索引(相同的数据块)时,则发生CACHE BUFFERS CHAINS LATCH争用的概率较高

Ø多个会话并发访问不同的表或者索引(不同的数据块)时,则发生CACHE BUFFERS LRU CHAIN LATCH争用的概率较高

问题:使用KEEP POOL能改善CBC LATCH争用吗?

   看情况。合理使用Keep Pool能有效减少物理读,即减少数据库pin CBC机会,从而减少CBC LATCH争用


FREE BUFFER WAITS

DBWR进程在写脏块完成(批处理写操作可以通过参数_db_block_write_batch来调整)之前,服务进程等待空闲缓冲区时会出现FREE BUFFER WAITS等待事件

通常是由以下原因引起的:

Ø低效的SQL

ØBUFFER CACHE过小

ØDBWR进程数量不足或者写脏块的速度不够快

Ø存储I/O问题

问题:如何判断DB CACHE是否已经足够?

看AWR报告中BUFFER CACHE建议一栏,另外BUFFER CACHE设置大没有坏处,但前提是不产生交换,CPU资源较充足


BUFFER BUSY WAITS

阻塞会话(BLOCKING会话)正在修改数据块时,想以当前模式访问的会话需要等待

v$session_wait中P1值代表数据文件号,P2值代表数据块号,P3值代表数据块类型

手动段管理方式(MSSM,即用FREELIST管理可用数据块)管理方式的段头在并发INSERT操作时容易引起争用

READ BY OTHER SESSION

一个以上的会话欲访问buffer cache上不存在的数据块时,发现该数据块正在被另外一个会话从磁盘读往缓冲区

往往伴随着DB FILE SEQUENTIAL READ或者DB FILE SCATTERED READ等待事件出现

突然出现大规模此类事件时,往往是执行计划不准确引起的


BUFFER CACHE大小的建议值

查询V$DB_CACHE_ADVICE

查看AWR报告中Buffer Pool Advisory


BUFFER CACHE内存不足的优化思路

加大buffer cache内存

调整糟糕的SQL语句写法或执行计划

DBWR进程数不足或者存储性能缓慢

提示:适当加大buffer cache内存是没有坏处的


BUFFER CACHE中数据块争用的优化思路

重新设计应用

让数据块中的数据尽可能地分散

Ø使用不同块大小的数据块

Ø修改数据块PCTFREE参数

Ø表中添加固定大小的列,增加冗余数据

Ø使用HASH分区表和HASH 簇表

Ø使用反转键索引(REVERSE INDEX)

Ø增大BUFFER CACHE

Ø合理使用KEEP POOL和RECYCLE POOL

Ø使用ASSM(自动段空间管理)

Ø加大数据块INTRANS参数

使用直接路径读写(DIRECT PATH I/O)

CPU紧张的系统中,适当减小BUFFER CACHE

RAC系统中,提高本地节点的BUFFER CACHE命中率

CPU、内存资源充足的情况下,增加buffer cache容量没有坏处,但前提是不要产生换页

三、详解SHARED POOL


SHARED POOL的主要内容

SHARED POOL从结构上可以大体分为如下几类:

ØPERMANENT AREA:进程/会话数据、ges resource等

ØLIBRARY CACHE

ØROW CACHE

ØRESERVED AREA

Ø

堆(HEAP)管理

SHARED POOL是利用堆内存管理(KGH heap Manager)方式管理

Oracle 9i开始,可以有多个最高级堆(TOP-LEVEL HEAP),最高级堆可以分为多个副堆

SHARED POOL,PGA,UGA,CGA可有多个高级堆


SHARED POOL的内存结构图

一个堆由多个内存区(EXTENT)以LINKED LIST的形式连接组成

EXTENT是物理上连续的内存区域

一个内存区由多个CHUNK组成

HEAP DUMP

CHUNK

分为以下几种状态(可以从视图x$ksmsp中查询):

ØFREE(可马上使用)

ØRECREATABLE(可再生)

ØFREEABLE(只有在SESSION或CALL期间内保存必要的对象状态)

ØPERMANENT(永久,不可再生)


FREE LIST

FREE LIST主要用于管理空闲的CHUNK。9i后,由256个BUCKET管理的,8i或者更早版本,只包含10个BUCKET

根据请求的chunk大小遍历合适大小的buckets,如果找不到合适的则遍历下一个buckets(bucket 0的内存碎片会越来越多)

分割产生的空闲CHUNK或者释放的CHUNK,会被挂载到相应的bucket上

分割连续的内存导致的内存碎片(chunk大小不一致),如下图:

注意:

(1)同一个BUCKET中的chunk不严格排序

(2)内存碎片是不可避免的,相邻的碎片会定时合并

如果literal SQL使用较多而且shared pool又很大,长时间使用后内部内存freelist上会产生大量小的内存碎片,使得shared pool latch被持有的时间变长,进而导致性能问题。在这种情况下,较小的shared pool也许比较大的shared pool好。因为 Bug:986149 的改进,这个问题在8.0.6和8.1.6以上版本被大大减少了。

合并shared pool碎片的方法:

SQL> alter system flush shared_pool;

注意: flush shared pool之后可能会导致:

Ø实例hang

Øsequence(cache属性)不连续

Ø过量的硬解析导致latch:shared pool争用


LRU LIST

主要保存着可以重建(recreateable)的chunk :

Øpinned (in use)

Øunpinned (inactive)

unpinned chunk主要分为2种LRU LIST:

ØTransient list:可能不会马上用到(cursor chunks)

ØRecurrent list:可能会马上用到(row cache chunks)


RESERVED FREE LIST

大小由参数SHARED_POOL_RESERVED_SIZE决定,默认为SHARED  POOL大小的5%。最大不能超过SHARED POOL大小的一半

只有大于_shared_pool_reserved_min_alloc隐含参数阀值(默认值为4400)的CURSOR才能进入RESERVED FREE LIST

只有高级堆有RESERVED FREE LIST

从Oracle 7.1.5首次引进,一般情况下,不常用到

查询V$SHARED_POOL_RESERVED

Ø如果REQUEST_FAILURES > 0

LAST_FAILURE_SIZE >SHARED_POOL_RESERVED_MIN_ALLOC

则:

(1)增加 SHARED_POOL_RESERVED_SIZE大小

(2)增加SHARED_POOL_SIZE大小

Ø如果REQUEST_FAILURES  > 0

LAST_FAILURE_SIZE<shared_pool_reserved_min_alloc< span=""></shared_pool_reserved_min_alloc<>

(1)减少_SHARED_POOL_RESERVED_MIN_ALLOC值

(2)增加SHARED_POOL_SIZE


Hidden free memory

实例启动之初分配shared pool内存的一半

不在free list中

使用后不再回收

从V$SGASTAT中可以观察:


SHARED POOL的内存分配顺序

进程在shared pool中分配内存的顺序:

(1)在FREE LIST查找合适大小的空闲CHUNK

(2)检索LRU LIST,查找recreateable unpined的CHUNK

(3)从父堆里分配空间

(4)自动扩展shared pool

(5)出现ORA-4031错误

注意:

(1)如果FREE LIST列表过长(即包含的FREE CHUNK过多),那么会话搜索可用的FREE CHUNK的时间可能会延长,从而导致持有SHARED POOL LATCH的时间更长

(2)如果达到了隐含参数_shared_pool_reserved_min_alloc的阀值,内存分配则从RESERVED FREE LIST中分配

Shared pool释放空闲内存顺序:

(1)释放没有上锁的对象

(2)释放带空锁的对象

注意:锁住/KEEP的对象是不能释放的


LATCH:SHARED POOL

扫描/分配/回收free chunk时需要申请latch:shared pool。如果free chunk过多则容易导致持有latch:shared pool过长。

注意:LATCH:SHARED POOL争用时,随意增大SHARED POOL的大小可能会更加恶化数据库性能


SHARED POOL的SUB POOL技术

Oracle 9i开始,SHARED POOL可以分为多个SUB POOL,其数量受以下几个因素影响:

Ø系统CPU的数量(A)

Ø共享池的大小(B)

Ø隐含参数_kghdsidx_count值(C

Oracle设置SUBPOOL大小的数量取值如下:

注意:NUMBER OF CONFIGURED SHARED POOL SUBPOOLS IS NOT CORRECT(Bug 4994956)

不同版本下的subpool的最小大小

每个SUB POOL拥有独立的FREE LIST、LRU LIST和SHARED POOL LATCH

从Oracle 10g开始,每个SUB POOL由4个SUB PARTITION组成

查询X$KSMSS获得每个SUBPOOL所分配的内存、剩余内存

查询X$KGHLU观察每个SUBPOOL发生ORA-04031的情况


关于SGA内存抖动

设置SGA_TARGET参数时,同时设置SHARED_POOL_SIZE和DB_CACHE_SIZE参数,使得SHARED POOL和BUFFER CACHE值维持在参数值之上,进而降低内存抖动的频率

设置的参考标准?


DICTIONARY CACHE

主要用于缓存Oracle数据字典

以行(Row)为单位存放,不是以块(Block)为单位,主要存放以下内容(dc_xxx对象):

ØTablespace

ØTable

ØIndex

ØSegment

ØView

ØUser

Ø

以下情况需要访问Dictionary Cache:

ØDDL语句

ØSequence.nextval

Ø需要访问对象、用户、空间等数据字典信息


ROW CACHE LOCK

主要用于保护row cache中的对象(objects)

用户访问row cache之前需要获得row cache lock:

引起row cache lock的原因:

Ø通常是高并发访问sequence(no cache)引起

Ø频繁访问柱状图信息

ØBug

可以通过v$rowcache_paraent查询holder和waiter:


enq:SQ-contention

主要用于保护以下场景:

ØSequence从dictionary cache中申请cache资源

Ø前台进程获取Sequence nextval


LIBRARY CACHE的内部结构

BUCKET主要由LIBRARY CACHE LATCH保护

HANDLE由LIBRARY CACHE LOCK保护

LCO由LIBRARY CACHE PIN保护


文章转载自DBA小记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论