内存结构(SGA system global area)是oracle为一个实例分配的一组共享内存缓冲区, 它包含该实例的数据和控制信息. SGA在实例启动时被自动分配, 当实例关闭时被收回. 数据库的所有数据操作都通过SGA来进行.
SGA中内存根据存放信息的不同, 可以分为如下几个区域.
数据库缓冲区(Buffer Cache): 存放数据库中数据库块的copy. 它由一组缓冲块组成,这些缓冲块为所有与该实例相连的用户进程共享. 缓冲块的数目由初始化参数DB_Block_buffers确定, 缓冲块的大小由初始化参数DB_BLOCK_SIZE确定. 大的数据块可提高查询速度.
日志缓冲区(Redo Log Buffer): 存放数据操作的更改信息. 它们以日志项(redo entry)的形式存放在日志缓冲区中. 当需要进行数据库恢复时, 日志项用于重构或回滚对数据库所做的变更. 日志缓冲区的大小由初始化参数LOG_BUFFER确定. 大的日志缓冲区可减少日志文件IO的次数. 后台进程LGWR将日志缓冲区中的信息写入磁盘的日志文件中, 可启动ARCH后台进程进行日志信息归档.
共享池(shared pool): 包含用来处理的sql语句信息. 它包含共享sql区和数据字典存储区. 共享sql区包含执行特定的sql语句所用的信息. 数据字典区包含用于存放数据字典, 它为所有用户进程共享.
Cursors: 一些内存指针, 执行待处理的sql语句.
其他信息区: 除了上述几个信息区外, 还包括一些进程之间的通信信息(如封锁信息); 在多线程服务器配置下, 还有一些程序全局区的信息, 请求队列和响应队列等.
Oracle用这一内存来防止不必要的数据块从磁盘重读. 理解oracle数据缓冲区如何操作, 是成功地运用它们调整数据库性能的关键.
在oracle8i之前的版本中, 当数据块被从磁盘送进数据缓冲区的时候, 数据块被自动地放置到最近使用过的数据列表的前部. 但是, 这种行为从oracle8i开始就变了: 新数据缓冲区被放置在缓冲区链的中部. 在调节数据库的时候, 你的目标就是为数据缓冲区分配尽量多的内存, 而不会导致数据库服务器在内存里分页. 数据缓冲区每小时的命中率一旦低于90%, 你就应该为数据块缓冲区增加缓冲区.
1.2.1 数据块的存活时间
在调入数据块之后, oracle会不停地跟踪数据块的使用计数(touch count, 也就是说, 这个数据块被用户线程所访问的次数). 如果一个数据块被多次使用, 它就被移动到最近使用过的数据列表的最前面, 这样就确保它会在内存里保存一段较长的时间. 这种新的中点插入技术会确保最常使用的数据块被保留在最近使用过的数据列表的最前面, 因为新的数据块只有在它们被重复使用的时候才会被移动到缓冲区链的最前面.
总而言之, oracle8i通过将新的数据块插入缓冲区的中部, 并根据访问活动调整缓冲区链, 每个数据缓冲区就被分割成两个部分: 热区(hot section), 代表数据缓冲区的最近使用的一半; 冷区(cold section), 代表数据缓冲区的最早使用的一半. 只有那些被反复请求的数据块才会被移近每个缓冲区的热区, 这就让每个数据缓冲区在缓冲常用数据块的时候效率更高.
热区的大小要用下面的隐藏参数来配置:
_db_percent_hot_default
_db_percent_hot_keep
_db_percent_hot_recycle
只有懂得内部机制和希望调节其数据缓冲区行为的有经验人员才应该使用这些参数.
1.2.2 找到热数据块
Oracle8i保留了一个X$BH内部查看表, 用来显示数据缓冲池的相对性能. X$BH查看表有下列数据列:
Tim: 两次使用之间的时间差, 和_db_aging_touch_time参数相关;
Tch: 使用计数, 它和被使用过_db_aging_hot_criteria次之后从冷区移入热区直接相关.
由于tch数据列用来追踪特定数据块的使用次数, 所以我们就可以编写sql查询来显示缓冲区里的热数据块—使用计数大于10的数据块.
SELECT obj object, dbarfil file#, dbablk block#, tch touches
FROM x$bh
WHERE tch > 10 ORDER BY tch desc;
这项高级查询技术在用于追踪DEFAULT缓冲池里的对象时尤其有用. 一旦定位了热数据块, 你就能够把它从default缓冲池移动到keep缓冲池.
select name,value
from v$sysstat
where name in ('physical reads', 'physical reads direct',
'physical reads direct (lob)', 'session logical reads');
select 1 - ((physical.value - direct.value - lobs.value) / logical.value) "Buffer Cache Hit Ratio"
from v$sysstat physical,
v$sysstat direct,
v$sysstat lobs,
v$sysstat logical
where physical.name = 'physical reads'
and direct.name = 'physical reads direct'
and lobs.name = 'physical reads direct (lob)'
and logical.name = 'session logical reads';
This v$sysstat view lists system statistics. To find the name of the statistic associated with each statistic number (STATISTIC#), query the V$STATNAME view.
Column |
Datatype |
Description |
STATISTIC# |
NUMBER |
Statistic number Note: Statistics numbers are not guaranteed to remain constant from one release to another. Therefore, you should rely on the statistics name rather than its number in your applications. |
NAME |
VARCHAR2(64) |
Statistic name |
CLASS |
NUMBER |
A number representing one or more statistics class. The following class numbers are additive:
|
VALUE |
NUMBER |
Statistic value |
1.4.1 修改data buffer cache的大小
调整database buffer cache的性能最简单的办法就是修改它的大小. 占SGA的45%最合适.
1, DB_BLOCK_SIZE主数据库块大小默认是8K, 在建立完数据库之后就不能改变.
2, DB_CACHE_SIZE(默认缓冲区池)默认48M, 我们主要修改这个参数以提高性能.
Alter system set db_cache_advice = on;
用oracle推荐的统计顾问, 在正常操作半个小时之后可以执行如下查询得到推荐的大小.
select name,size_for_estimate,v$db_cache_advice.ESTD_PHYSICAL_READS from v$db_cache_advice where block_size='8192' and advice_status='ON';
另外, 我们可以通过下述语句查询哪些对象正缓存在buffer cache中, 正使用多少个buffer cache缓冲区.
select do.owner,do.object_name,do.object_type,count(distinct a.BLOCK#) "NUM of buffers"
from v$bh a, dba_objects do
where a.OBJD = do.object_id
and do.owner = 'CTL'
group by do.owner,do.object_name,do.object_type
3, 使用多个缓冲池
Alter system set db_cache_size = 300M;
Alter system set db_keep_cache_size = 150M;
Alter system set db_recycle_cache_size = 30M;
将表分配给保持区.
Alter table col_cust storage(buffer_pool keep);
使用下面语句可以查看分配情况.
select owner,segment_type,segment_name,buffer_pool
from dba_segments
where buffer_pool != 'DEFAULT';
使用下面语句可以查看每个buffer pool的大小以及buffer cache的命中率.
select name "Buffer Pool",
1 - (physical_reads / (db_block_gets + consistent_gets)) "Buffer Pool Hit Ratio"
from v$buffer_pool_statistics
order by name;
4, 在内存中缓存表
虽然表可以放在保持区, 但是由于keep pool也是由LRU控制的, 所以当FTS(full table scan)时, 该表还是被放在LRU的最近最少使用那端. 这样就有可能被移出. 所以我们可以将表变成一个高速缓存区表.
Alter table col_cust cache;
Select owner, table_name from dba_tables where ltrim(cache)=’Y’.