1、Overview:
Oracle shared server主要用于允许多user进程能够共享有限数量的servers。
在dedicated server环境中,每个user 进程都会分配到一个server进程,但如果这些server进程不能完全被利用,常处于idle状态,就会造成内存和cpu的浪费。
当使用shared server模式,user进程是动态的被分配到可以被任何user进程共享的server进程上的。当dispatcher进程获得一个user 进程请求后会将其放入请求队列,以便server进程可以处理该请求并将结果返回给dispatcher的response队列。随后 dispatcher进程会将response队列中的结果返回给user进程。
Oracle Shared Server主要用于下面的情况:当dedicated Server的系统对于system开销相对较大;在访问的资源上存在限制。
2、对dispatchers的监控:
1)可以通过v$MTS视图获得关于连接和session的会话以及当前使用的使用的数据信息。如果sessions的设置低于实际的dispatcher的设置,MAXIMUM_CONNECTIONS的默认值是参数SESSIONS的值。
2)V$DISPATCHER视图查询dispatcher的繁忙率:
select network “protocol”, status “status”, sum(owned) “clients”, sum(busy) * 100/(sum(busy)+sum(idle)) “busy rate” from v$dispatche group by network;
note:在选择dispatcher数量的时候,应该考虑客户端的数量对于dispatcher的繁忙比率。如果一个dispatcher的繁忙比率 超过50%,就需要考虑增加dispatcher的数量。如果发现部分dispatcher经常处于idle的状态,应该考虑减少dispatcher的 数量。
可用下面的SQL查看users sessions是否在等待dispatchers:
select decode(sum(totalq), 0, ‘no responses’, sum(wait)/sum(totalq)) “average wait time” from v$queue q, v$dispatcher d where q.type = ‘DISPATCHER’ AND q.paddr = d.paddr;
如果观察到大量的等待比率并不断增长,需要考虑增加dispatcher的数量。
增加或减少dispatcher使用:
alter system set mts_dispatchers = ‘protocol, number’;
执行上述语句后只有新的连接建立才会使用new增加的dispatcher。
2)此外,可以使用视图V$DISPATCHER_RATE视图来分析冲突。它分组显示了cur、avg、max的统计信息。如果使用shared Server的性能不理想,则cur的值将接近max的值,对此应该考虑增加dispatcher的数量。如果发现shared Server性能良好,cur值远远低于max的值,可以考虑降低dispatcher的个数。
3、对Shared Server的监控:
当PMON后台进程发现当前存在的shared Servers都处在忙碌状态,Oracle shared Server进程就会被是动态创建的创建。当然此时MAX_SHARED_SERVERS的值必须大于实际的servers值。当然,如果PMON检测到 当前有shared servers存在idle状态的,则会减少相应的shared servers的数量,直到数量达到SHARED_SERVERS的值。所以不必太多的考虑shared servers的状态。但是有时需要调整SHARED_SERVERS和MAX_SHARED_SERVERS的参数的大小。
对此,可以使用视图V$SHARED_SERVER视图获得shared servers的当前信息。
select name, requests, busy*100/(busy+idle) “busy %”, status from v$shared_server where status != ’QUIT’;
此外,可以查看每个请求的平均等待时间:
select decode(totalq, 0, ‘No Requests’, wait/totalq ||’ hundredths of seconds’ )”Average Wait Time Per Requests” from v$queue where type = ‘COMMON’;
4、监控进程的作用:查看共享连接。如果觉得user程序有问题或是某个进程似乎做了很多操作,可能需要查看当前user的共享连接。对此可以使用 v$session视图查看应用的状态和使用的连接类型,可以使用v$circuit获得相应的server、session和dispatcher的 addresses。
5、shared server和memory 使用:之前有说过,当使用shared server模式时,部分称为UGA(user global area)的数据将被存放在shared pool中,同时session的data Components被存放在large pool中。如果没有设置large pool,将存放在shared pool中。
从总体将使用shared server模式,内存的开支减少了。
shared servers使用UGA用于sorts,此模式下,应该设置SORT_AREA_RETAINED_SIZE相对小于SORT_AREA_SIZE,以便可以快速释放内存给其他user。
6、troubleshooting:常见问题有:
1)所有共享连接都失败时,查看Oracle net listener在running。
2)查看是否在建立shared connection时存在Oracle net配置的错误”TNS_”
3)不要轻易在OS层kill掉user的server进程,建议使用alter system kill session。如果使用dispatcher连接的,kill掉dispatcher进程会更糟,会影响其他user。
4)dispatchers和servers都是后台进程,所以在设置PROCESSES时要考虑相应的数量。
5)如果参数INSTANCE_NAME, SERVICE_NAMES 或 DB_DOMAIN 没有被设置,或是设置不正确,则其不能进行自动instance注册。
• V$CIRCUIT: Contains information about user connections to the database
• V$DISPATCHER: Provides information on the dispatcher processes
• V$DISPATCHER_RATE: Provides rate statistics for the dispatcher processes
• V$QUEUE: Contains information on the multithread message queues
• V$MTS: Contains information for tuning the Oracle shared server
• V$SESSION: Lists session information for each current session
• V$SHARED_SERVER: Contains information about the shared server processes
eg:
SELECT d.network network, d.name disp, s.username oracle_user,
s.sid sid,s.serial# serial#, p.username os_user,
p.terminal terminal, s.program program
FROM v$dispatcher d, v$circuit c, v$session s, v$process p
WHERE d.paddr = c.dispatcher(+)
AND c.saddr = s.saddr(+)
AND s.paddr = p.addr (+)
order by d.network, d.name, s.username
1、选择适当的物理结构:为了达到读写尽可能快的目的,必须考虑下面的问题:
1)如果application对rows的访问是按照groups进行的,则需要考虑使用clusters的方式才存储,但clusters对于大量的DML操作会影响性能,所以要考虑application中DML和select操作的数量。
2)对于较大规模的表,使用单独的表空间。对于一个partitioned表,考虑使用多个表空间,从而平均分配磁盘的使用。
3)对于9i中可以允许在同一个DB中有多block size,因此,row size较大的可以有较大的block size。如果设置较大的block size,有助于全表扫描的应用的性能提高。
4)对于小的small transaction占用undo space的回滚信息少,大transaction占用的undo space多,所以所需的free undo space多。
5)对于较大的查询,可以考虑使用多server 进程进程并发查询。
2、数据的访问方法:为了提高性能,可以使用下面的数据访问方法:clusters;indexes:b-tree(普通和翻转关键字)、位图、Function based;索引组织表;固化视图。
1)Clusters:是将一组一个或多个因为有共享columns所以有相同数据块的表放在一起的方法。这些数据块会经常被同时访问或join。这种方法可以使DBA对数据库非规范化,而对user和programmer是透明的。
它在一定程度上降低了磁盘I/O,使用clustered table可以很好的改善join的效率。每个cluster关键字对于多行且值相同的情况下,只会存储一次,所以占用存储空间较小。
但是对于全表扫描,clustered表比nonclustered 表慢很多。
cluster的类型有:
①index cluster:它使用一个被称作cluster index的索引维持cluster中的数据。在index cluster中,对数据的维护、访问、存储cluster index必须是可用的。cluster index用于指向包含给定关键字值的rows的block位置。与普通index不同的是cluster indexes会存储null 值。对于每个cluster index中的关键字,只有一条记录。所以一个cluster index会比普通index的占用空间小。
②hash clusters:它使用hash算法(也已user定义,也可系统指定)计算row的位置。用于查询和DML操作。对于等值查找clusters key,hash cluster的性能要比index cluster的好。
不应使用clusters的情况:经常执行全表扫描的情况;如果对于所有rows的cluster key的数据超出了一到两个Oracle blocks,这样,为了访问在clustered key table中的一条row,Oracle server需要读取有相同值的所有blocks。
不应使用hash clusters的情况:如果表不断增长,并且重建新的、更大的hash cluster不可能的情况下,不应使用hash cluster;如果application经常使用full scans,并且要考虑为table的增大所必须预留的空间。
2)B-Tree indexes:
①使用B-Tree index的情况:当经常访问表中的记录占全表的不足5%时,应该考虑创建B-Tree index;如果在查询时,indexes可以包含所有要访问的字段,这个百分比可以更高些;或是对可以用于进行表的join时,也应考虑建立B- Tree index。
②indexes的增长方式:index总是平衡的,总是自下而上的增长。当rows被增加时,会添加到叶子节点的block上,如果叶子节点的 block被填满,Oracle server会将该block split成两个叶子blocks,每个保存50%的数据。因为新block的添加,叶子节点的父节点也需要添加相应的blocks索引值。如果父节点的 block被填满,父节点也会被split成两个节点,类似与刚才的子节点的split。这个过程会循环进行,直到b-tree保持平衡。index的层 次越多,其效率越低。此外,对于delete操作,会降低index的效率,特别是当有15%的rows被删除,应该考虑rebuilding index。
③为了提高b-tree index的性能,应该定期对index进行rebuild。自9i,可以online创建、rebuild indexes,并且可以并行化进行。当index被rebuild时,相关的table仍然可以被访问和进程DML操作。
ALTER INDEX i_name REBUILD ONLINE;
–ONLINE关键字表示在rebuild时,DML仍可进行。但是不允许并发的DML操作。
④压缩索引:
在创建索引时使用下面的方法可以对index进程压缩:
create index i_name on t_name(col1, col2) compress;
重建索引时可以使用:
alter index i_name rebuild compress;
压缩索引不会多次存储重复出现的关键字从而减少了存储空间的需求。
对于非唯一索引的压缩:Oracle存储重复的关键字作为前缀在index block中,唯一的row id作为后缀存储。
对于唯一索引的压缩:也是类似的,将一致的前缀只保存一次,用于区分唯一性的部分会作为后缀存储。但是这只适用于有多个字段组成的唯一索引,如果只有一个column的唯一索引没有用于share的部分。
3)位图(bitmap)索引:主要适用于distinct的values很少的字段,在其上建立索引。例如性别、工种等字段。但是对于有大量DML操作的表,bitmap index的性能不好,此情况应慎用。
① 适用bitmap index的情况:对于基数较低(low-cardinality)的column创建的索引;如果查询语句中使用多个where条件,Oracle server可以使用逻辑的bit-and或bit-or操作来合并不同columns的bitmaps。
②性能的考虑:bitmap index占用空间较小,每个distinct key的存储时以压缩的方式,bitmap被分成不同的bitmap segments;对于low-cardinality字段非常快;很适合与规模大的只读系统,如决策支持系统(DSS);但是对于DML操作性能比较 慢,不适用于OLTP应用,locking是加载在bitmap-segment上的,不是在记录上的;bitmap index是存储null值的,但b-tree不存储;并发查询、并发DML和并发的CREATE语句在bitmap indexes上是有效的。
③bitmap indexes的创建及管理:
create bitmap index i_name on t_name(col1) storage ( initial 200k next 200k pctincrease 0 maxextents 50) tablespace tsp_name;
对于每个DML操作之后,会对bitmap indexes进行相应的维护,所以对于每个DML操作,每个bitmap segment只会更新一次,既是该bitmap segment中不只一行更新数据。
4)反转关键字索引(reverse key index):在创建索引时会将索引字段按bytes进行反转(reverse)随后将结果作为索引关键字。
①对于一个不断增长的关键字,如由sequence产生的id,可以通过使用reverse key index避免索引的不断split。但是对于常使用范围查找的应用,只能使用全表扫描。
②创建reverse key index:
create index i_name on t_name(col1) reverse pctfree 30 storage( intial 200k next 200k pctincrease 0 maxextents 50) tablespace i_tspname;
或者
create index i_name on t_name(col1);
alter index i_name rebuild reverse;
5)组织索引表(IOT——index-organized table):类似与mysql中的innodb的存储结构,具体结构如下图:
适用于频繁通过primary key或primary key的前缀访问数据的情况。但是必须要求有primary key的限制。它加快了通过key查找数据的速度,并且从table和index整体上节省空间。
①在IOT中,没有常规表中的那种物理上的row id的概念,而是引入了逻辑row id的概念,它是以变长的方式存储的,其size要依靠primary key的值。
对于IOT中数据的访问有两种方法:
i)物理猜测guess,访问时间等同于物理rowid的访问时间
ii)当guess失败,则通过primary key访问IOT中的数据
(guess就是基于row所在的文件和block访问,block的地址在表建立时是精确的,但是如果leaf block进行了拆分split是,就发生了改变。如果guess失败,则通过primary key进行访问。)这里没太搞懂啊:(
②创建
CREATE TABLE countries
( country_id CHAR(2) CONSTRAINT country_id_nn NOT NULL,
country_name VARCHAR2(40),
currency_name VARCHAR2(25),
currency_symbol VARCHAR2(3),
map BLOB,
flag BLOB,
CONSTRAINT country_c_id_pk PRIMARY KEY (country_id))
ORGANIZATION INDEX
PCTTHRESHOLD 20
OVERFLOW TABLESPACE USERS;
影响IOT的行溢出的三个主要因素有:
** pctthreshold:此子句指明了在index block中容纳一行数据可使用块空间的百分比。如果one row数据超过基于此值计算的大小,所有的在including子句之后的字段将被移入overflow segment。如果overflow没有被定义,则这种row溢出转移将被拒绝。PCTTHRESHOLD默认值是50必须在0到50之间。
** including:后跟一个字段,如果数据行的长度超过了PCTTHRESHOLD指定的可用空间,从这个字段之后将数据行分为两段,后面的部分放入溢出段中;
** overflow TABLESPACE :指明当index-organized表数据超出pctthreshold时,将部分columns放入data segment。
③IOT的字典视图:
④使用mapping table
create table countries
( country_id char(2) constaint country_id_nn not null,
country_name varchar2(40),
currency_name varchar2(25),
currency_symbol varchar2(3),
constraint country_c_id_pk primary key (country_id))
organization index mapping table tablespace users;
当在索引组织表上创建位图索引同heap table上创建bitmap是类似的,只是在组织索引表中的rowid对应的不是基础表,而是相应的映射表(mapping table)。mapping table主要是维护一个逻辑row id(访问组织索引表所需的)到physical row id(访问位图索引所需的)的映射。每个组织索引表会有一个mapping table,用于全表的映射。在heap organized base table中,用key访问数据时,如果找到相应的key,bitmap记录返回的是物理row id,可以用于基础表的访问。在组织索引表中,位图索引也是用key进行搜索,当找到相应的key,bitmap返回的依然是物理row id,通过查询mapping table,获得相应的逻辑row id,再用于进入guess data block address或是用primary key访问组织索引表
组织索引表中的row发生移动,不会使其上的bitmap indexes不可用,只是使mapping table中的相应逻辑row id不可用,但仍可通过primary key对其进行访问。
对于mapping table的维护:
** 通过对IOT表进行analyze获得mapping table的统计信息
** 查询DBA_INDEXES视图得知当前mapping table的精确度
SELECT INDEX_NAME, PCT_DIRECT_ACCESS FROM DBA_INDEXES WHERE PCT_DIRECT_ACCESS IS NOT NULL;
** 如果需要,使用alter table重建mapping table
alter table t_name mapping table update block references;
6)物化视图(Materialized views)
物化视图既存储视图的定义,又存储视图创建语句的查询结果。可以将物化视图定义的结果会产生一个实际的表,可以对其做类似normal table的定义,将其指派的某个表空间,对其添加索引,进行分区等。如果通过固化视图就可以满足的查询,server会将查询转换为对物化视图的查询, 而不是对基础表的查询。这样,部分代价昂贵的如join或统计的查询就不必重复执行。
①创建:
create materialized view depart_sal_sum
tablespace data parallel (degree 4)
build immediate|deferred refresh fast
enable|disable query rewrite
as
select d.departmet_name, sum(e.salary) from departments d, employees e
where d.departmant_id=e.department_id group by d.department_name;
②refresh 物化视图:具体有两类:
i)完全的refresh:主要是通过truncate 当前的data,通过执行物化视图的创建语句重新插入数据。
ii)fast refresh方法:它只会更新自上次refresh之后发生变化的数据。具体又有两种:
** 使用materialized view logs:此方法中,所有关于视图的基础表的变化都会被捕获并记录到一个log中,将这些log data用于materialized view即可。
** 使用row id范围:此方法需要一个直接装在日志。记录了需要被重新load的row id相关信息。materialized view就利用这些row id进行直接路径的load。
一个视图的定义使用force的refresh类型时,会尽可能的使用fast refresh方法,不得已才会使用complete refresh。默认情况是使用force refresh类型。如果使用never选项,则会抑制所有materialized view的refresh。
③自动refresh可以通过下面方法设置:
** 如果为materialized view设置oncommit选项,视图会在base table每次commit操作后进行refresh。因为操作时异步的,所以不会让user察觉到性能的降低。
** 在具体的时间点:可以使用START WITH和NEXT子句定义每次refresh的具体时间。为了实现此方法,必须将参数JOB_QUEUE_PROCESSES设置为大于0的值。
④可以用DBMS_MVIEW包进行手动的refresh。
** 对具体的某个materialized view进行refresh
DBMS_MVIEW.REFRESH(…)
** 对依赖某个基础表的所有物化视图进行refresh
DBMS_MVIEW.REFRESH_DEPENDENT(…)
** 对所有的materialized view进行refresh
DBMS_MVIEW.REFRESH_ALL_MVIEWS;
为了执行手动refresh job,必须为其设置适当的JOB_QUEUE_PROCESSES和JOB_QUEUE_INTERVAL参数。
⑤物化视图的查询重写(query rewrite):这一过程是通过优化器(optimizer)完成的,对于应用而言是透明的。可以加速对基础表的部分访问。user不需要被明确的赋予 materialized view的权限,只要其有base table的权限,则其发出的相关查询就可以被重写为对物化视图的访问。materialized view也可设置为enable和disable。
进行query rewrite,必须使QUERY_REWRITE_ENABLED设置为true。对于使用query rewrite的user必须有GLOBAL QUERY REWRITE或QUERY REWRITE的权限。后者只允许user对自己schema下面的materialized view进行query rewrite,前者除此还可对其他有权限的schema进行query rewrite。
⑥物化视图在带来效率的同时也会增加占用的额外空间,并且需要refresh的开支。对此在DBMS_OLAP包的sumary advisor可以用于对代价与收益的比较从而辅助觉得materialized view的创建。
vii)对query rewrit的控制分为三个层次:
** 在初始化参数级别上:
OPTIMIZER_MODE:查询重写只有在cost-based优化模式下才能进行。可在session级别动态设置;
QUERY_REWRITE_ENABLED:可设置为true或是false,可在session级别动态设置;
QUERY_REWRITE_INTEGRITY:可设置为ENFORCED(默认值,只有server能确保一致性时——物化视图是最新的并且 query rewrite使用了有效的验证约束的情况下才进行query rewrite)、TRUSTED(物化视图是最新的,此外相信RELY的约束, 就算这个约束没有Enabled和Validated)、 STALE_TOLERATED(query rewrite允许使用没有及时refresh的物化视图)。此参数也是可以在session级别上动态设置的。
** 在sql中使用hints——REWRITE和NOREWRITE,它可以覆盖在创建或alter物化视图是设置的enable query rewrite子句。
** dimensions(这个也没太懂~~~~(>_<)~~~~ )
viii)可以使用dbms_mview包中的EXPLAIN_MVIEW和explain_rewrite对materialized view和query rewrite进行解释。
3、OLTP系统:
主要特点是:集中的insert和update操作,数据不断增长,多事务并发进行。要求高可用性、高速、高度并发、降低恢复时间。
1)空间分配:避免动态的空间分配,应该为tables、cluster、indexes明确指明占用的tablespace。此外通过观察数据增长的规律,设计extent每次分配的大小。
2)indexes:在DB中indexes的创建和维护都是占用一定开支的,所以,索引的创建必须严谨,每个索引的存在必须是实际需要的;在外键上建立 索引有助于在子表数据被修改时不会locking父表中的数据;b-tree索引在OLTP中优于位图索引,因为locking对DML的影响(当DML 操作发生时b-tree索引中只是锁某些rows,但bitmap索引,会locking整个有相同key的rows);可以考虑使用reverse index来解决b-tree中sequence columns的问题;应该定期对indexes进行rebuild。
3)hash clustering:使用hash clusters可以提高等值查询的访问速度。但是对于下面的情况则不适用它:
** 大量insert操作
** 存在大量用更大的columns values对表进行update的操作,因为会引起数据的迁移。
如果表不断增长,可能在hash key上存在大量冲突,从而是部分数据存放在overflow blocks中,为了避免这种情况,正确的评估hashkeys的值。给hash key更大的number,有助于解决冲突。
4)OLTP Application Issues:
* 对于完整性约束,应该使用DB中声明的constraints代替application中code的逻辑限制。这里主要考虑的是参照完整性和约束的check。
* 应该考虑使用Oracle中的共享code对象,如packages、procedures和Functions。
* 应该尽可能使用绑定变量
* 定义恰当的cursor_sharing参数,有助于user共享解析代码。可设置的值有:
EXACT:默认值,只在精确匹配的情况下共享cursors
SIMILAR:如果SQL语句是字面量,则只有当已有的执行计划是最佳时才使用它,如果已有执行计划不是最佳则重新对这个SQL语句进行分析来制定最佳执行计划。
FORCE:如果SQL语句是字面量,则迫使Optimizer始终使用已有的执行计划,无论已有的执行计划是不是最佳的。
4、决策支持系统(DSS/Data Warehouses)
DSS的特点是该application会提取相应的有用数组成容易理解的报表。将OLTP中的数据进行提取、整合、汇总。使用大量的全表扫描。决策者根 据相关的结果做下一步的决策。它需要有快速的响应时间,并且数据应该确保精确。并发查询的特点就是为了data warehouse环境设计的。
1)存储的分配:
* 谨慎的考虑block size和DB_FILE_MULTIBLOCK_READ_COUNT参数的设置。可以考虑适当增大block_size、DB_FILE_MULTIBLOCK_READ_COUNT。
* 确保extent的size是block_size的整数倍。
* 定期执行analyze或是dbms_stats进行表的statistics。
2)indexing:因为大量的查询是通过全表扫描完成的,所以应尽量减少index占用的空间和对其维护带来的开销。
* 可以的话,可以考虑不使用索引,只保留那些需要用于进行筛选查询的index;
* 定期的用不一致的分布数据产生直方图。
* 考虑使用bitmap indexes
* 对于需要快速用关键字查询的data可将相应的表建为IOT。
* 考虑使用index和hash cluster,特别是hash cluster。但不要在定期批量增长的表上建立cluster。
3)application issues:
在data warehouse中,sql的解析时间并不重要,所以可以适当的减小library cache的大小。应该更关注执行计划:尽量使用并发查询。Symmetric multiprocessors (SMP), clustered, or massively parallel processing (MPP)将能很好的提高性能。SQL的调节优化很重要。
有时可以弃用绑定变量,因为:当analyze后产生直方图,可以用于一定的查询优化,但是这种优化只使用在不使用绑定变量的情况。如果使用绑定变量,则optimizer就不会使用直方图了。对此要小心设置cursor_sharing参数的值。
5、混合系统(Hybrid System)
1、对于闩(Latches)的概览
Latches是为了保护SGA中的共享数据结构而创建的简单的底层的序列化机制,是轻量级的锁。server或后台进程为了操作或是查看共享数据结构必 须先申请Latches,当操作结束,需要释放Latches。Latches的争用是不用tuning的,它是不合理使用SGA资源的征兆,需要 tuning内部的争用。仅仅是观察v$LATCH是不足的,但可以将其看做是诊断工具,查找SGA资源争用的位置。
1)Latches的目的:
* 控制序列化访问:保护SGA中的数据结构;保护共享内存的分配。
* 序列化执行某些操作:避免同时执行某些关键的临界code;避免corruptions。
2)等待Latch
尽管latch的实现根据不同的OS和平台而不同,但是其都是内存中的一块地址空间,当latch空闲时是0,已经被申请了时为非0值。
在单cpu中,当进程p1申请的latch被占用,p1将释放cpu,sleep一小段时间,等待latch被释放。
在多cpu中,如果进程p1申请的latch被p2占用,很可能p2在其他的cpu上,则p1不会释放cpu,而是spin计数,重试,spin计数,重试,直到重试次数达到设置数,仍未成功,才会释放cpu,但这种可能比较小。
3)Latch的请求类型:
latch的请求方式有两类:willing-to-wait和immediate。
willing-to-wait:当进程申请一个latch时,如果当前latch已经被占用,该进程会等待片刻再重试,等待-重试,直到获得latch,这是一般普遍的latch申请方式。
immediate:如果进程申请的latch不能获得,该进程会继续执行后续的指令。
4)latch 冲突:latch的申请释放都是Oracle自动实现的,所以速度比较快。latch的资源是有限的。
在诊断latch时,可利用视图v$latch,该视图中主要columns的意义:
• gets: Number of successful willing-to-wait requests for a latch
• misses: Number of times an initial willing-to-wait request was unsuccessful
• sleeps: Number of times a process waited after an initial willing-to-wait request
• wait_time: Number of milliseconds waited after willing-to-wait request
• cwait_time: A measure of the cumulative wait time including the time spent spinning and sleeping, the overhead of context switches due to OS time slicing and page faults and interrupts
• spin_gets: Gets that missed first try but succeeded after spinning
• immediate_gets: Number of successful immediate requests for each latch.
• immediate_misses: Number of unsuccessful immediate requests for each latch.
在使用statspack是,可先查看其report的top 5 wait events部分,是否有latch free事件,如果有再进行后续的分析。
2、降低Latches的冲突
一般,DBA不应该调节latches的数目,自9i以来,Oracle已经可以自己进行latches数量的调节了,这主要是根据DB在建立时设置的初始参数和OS的环境。
latches的冲突是性能问题的表现。最好的解决latches冲突问题的方法是修改application行为。此外,如果观察到是buffer或shared poolsize的问题,也需要进行适当的修改。
3、对DBA而言,几个重要的latches
1)shared pool latch和library cache latch:如果冲突出现在这两类latch上,则表示sql或是pl/sql命令没有被有效重用,可能是没有有效的使用绑定变量,或是cursor cache不足。如果是Oracle Shared server模式,如果没有设置large pool,也可能导致Shared pool Latch的冲突,则需要考虑设置large pool。
2)cache buffer lru chain latch:当dirty blocks被写入disk或server进程查找blocks用于写入操作时会request此latch。如果它存在较大冲突,则表示buffer cache任务繁重,可能存在较多的cache-based sorts、低效的SQL(使用了不正确的迭代索引)或是较多的全表扫描。此外,也可能是由于DBWn的写速度跟不上data blocks的变化速度。使得访问进程不得不为了找到buffer中的free blocks等待。对这个latch的冲突,应该从buffer cache或DBWn的调节入手。
3)cache buffers chains latch:当user进程试图分配buffer cache中的data blocks时,需要申请此latch。它的冲突反映了某些热块被重复访问的情况。
4、共享池和library cache latch冲突:如上所述,此类冲突的一个主要原因是不必要的解析。其调节方法已经在之前介绍过了。
1)辨识因为拼写方式而造成的多次解析:
select sql_text from v$sqlarea where executions=1 order by upper(sql_text);
2)查看是否有不必要的重复解析。
select sql_text, parse_calls, executions from v$sqlarea order by parse_calls;
1、rollback segments的作用:事务的rollback;transaction recovery(当事务尚未提交或rollback时instance fail,startup时会用rollback segment进行回滚恢复);读一致性也需要rollback segment进行数据的还原。在新的版本中(我记得是从10g中)flashback技术也使用了rollback segment。这里先不介绍了,碰到时在说。
2、rollback segment的activity:
1)transaction以顺序循环的方式使用rollback segment中的extents。一个transaction在rollback segment的当前位置写入记录,并将指针移动写入记录的大小的步长。写入rollback segment的请求需要相应的undo data在database buffer cache中是可用的。这就要求有较大的buffer cache。
2)注意:多个transaction可以对一个rollback segment中的同一个extent进行写操作。每个rollback segment block只会包含一个transaction的数据信息。
3)rollback segment header中包含了不同transaction各自的记录:Oracle server在每个rollback segment header中保存一个transaction tables,从而控制改变rollback segments中data block的操作。
因为需要不断修改,所以rollback segment header block被长期保存在data block buffer cache。而不断的访问rollback segment header block会增加命中率。这种影响对于某些有大量小型事务的OLTP的application影响较大。每个transaction都需要修改 transaction tables,所以必须有足够大的rollback segment从而避免对transaction tables的冲突。低估rollback segment的需求,可能引起性能问题或errors。高估会浪费空间。可以使用自动undo表空间管理的方法管理undo segments。
4)rollback segments的增长:
当当前extent写满后,指针或是rollback segment的头回移动到下一个extent。当最后一个extent作为当前写入的extent,被写满后,如果此时第一个extent是free 的,则指针将指向第一个extent的开始。指针式不能跳过(skip over)extent,移动到后面的extent上的。所以如果第一个extent仍被使用,将会为此rollback segment分配一个新的extent。这被称作extend。
在正常的运行期间,rollback segments不应该被extend。所以在之前应该分配足够的rollback segment空间。应该尽量避免动态空间的管理。
2、调节手动管理的rollback segments
1)调节rollback segment的目标:
* 尽量使transaction不会为访问rollback segment而等待:这需要有足够的rollback segment
* 在运行期间,应避免rollback segment的extend:
需要每个segment有适当数量的extents
extents的四则应该正确
适当数量的rollback segment
尽量减少应用中对rollback的应用
* 应该没有transaction把rollback space占用完:对此应该将较大transaction用多个transaction替代
* 数据查询user应该总是能获得读一致的数据:这需要考虑设置适当数量的segments和适当的segments size。
2)诊断工具:常用的监控视图有:
* V$ROLLNAME:显示了在线rollback segments的名字和数量
* V$ROLLSTAT:显示了每个在线rollback segment的统计信息。等待header transaction tables的数量,transaction写数据的卷标等信息。
* V$WAITSTAT:显示等待header blocks和rollback segments的blocks累计数量。undo header和undo block两条记录。
* V$SYSSTAT:显示
select name, value from v$sysstat where name like ‘%undo%’;
* V$TRANSACTION:显示当前transaction使用的rollback segment和require的空间的卷标。
在查询时需要用视图中的USN作为连接字段。
3)对手动管理的rollback segment header冲突的诊断
查看:v$rollstat中的waits字段;v$waitstat中的undo header行;
select event, total_waits, time_waited from v$system_event where event like ‘%undo%’;
select class, count from v$waitstat where class like ‘%undo%’;
select sum(value) from v$sysstat where name in (‘db block gets’, ‘consistent gets’);
select sum(waits)*100/sum(gets) “ratio”, sum(waits) “waits”, sum(gets) “gets” from v$rollstat;
当等待的比率大于1%,则考虑创建更多的rollback segment。
4)对于手动管理的rollback segment的数量的考虑
* 对于OLTP application,其特点是有大量的小transaction并发,每个transaction只修改很少的数据量。对此可以设置small rollback segments。一般的设定规律是,并发的transaction中,每4个设置一个rollback segment。
* 如果对于存在较大的批量transaction时,如果rollback segment较小,就可能会发生extend。允许rollback segment可以无限自行extend。
* 如果想要给long transaction分配large rollback segment,可以使用下面的语法:
SET TRANSACTION USE ROLLBACK SEGMENT large_rbs; –必须是事务的第一句
或
execute dbms_transaction.use_rollback_segment(‘large_rbs’);
5)Sizing 手动管理的rollback segment的大小
设置适当的rollback segment size一方面可以避免动态的extend,另一方面当undo blocks被请求时增大了它在cache的可能性。
* 对于small transactions设置segments的initial参数为8KB、16KB、32KB或64KB,对于larger transaction设置为128KB、256KB、512KB、1MB、2MB、4MB等。该值应该设置的足够大,以免出现wrapping现象(当 一个rollback entry在当前使用的空间中找不到足够的空间时,被写入下一个extent)。
* 使用与initial相等的数值做next的参数值。因为PCTINCREASE设置为0,所以后续所有的extents都将是next大小。
* 将DB中的所有rollback segment都设置为相同的size。如果暂时不需要large rollback segment,可以先将其offline。
* 将minextents参数设置为20 。这大致可以避免extend的现象。
* 对于表空间的size设置,我以为书中没有介绍太多的方法,需要在实际应用中查看产生的undo entries的数量进行设置。此外,可以为其保留一个专门用于large-than-usual transaction的segment。
3、transaction rollback data的sizing
1)不同的sql操作所产生的rollback data的大小有下面而定:
* delete操作对rollback segment的开销很大,会存储实际row的数据。如果使用truncate,则会对性能有所改变,但是因为没有写rollback entries,所以不能再恢复。
* insert 使用的rollback space很少,只会记录row id。
* update操作占用的空间要依靠修改的字段数量而定。
* indexed 值将会产生较多rollback。因为server在修改index的同时需要修改tables中row,对于对index字段的update操作,需要 记录old data value、old index value和new index value。
note:lob数据类型的回滚数据不使用rollback segment space,而是占用其自己的segment中由参数pctversion定义的大小的空间。
可以通过下面的sql查看当前事务产生的rollback data
select s.username, t.user_ublk, t.start_time from v$transaction t, v$session s where t.addr, s.taddr;
2)另一种衡量方法是,实际执行相应的操作,从而观察rollback segment的变化
* 在执行操作前运行:select usn, writes from v$rollstat;
* 执行测试的事务操作
* 再次查看rollback segment的统计数据:select usn, writes from v$rollstat;
4、使用产生少量rollback data 的语句:
* user应该尽可能有规律的commit,避免其transaction锁住外部的rollback segment extents。
* 开发人员应该在code时不使用long transaction。
* import操作时,指定commit=y,使得每插入一定数据后就进行commit;用buffer_size关键字设置rows集合的大小。
* export操作时:设置参数consistent=n,避免该是我被设置为只读,那将占用更多的rollback segment space。consistent=y时,确保了导出的数据在一个时间点上是一致的。
* sql*loader:在执行时也应用rows关键字设置commit interval。
note:对于小rollback segments可能带来的问题有:
* interested transaction list(ITL)被存放在block的header。每个ITL entry都包含了发起此处变更的transaction id、undo block的位置、标识位、空闲空间credit和SCN。row lock byte包含了ITL实体number,就相当于该transaction拥有该row的锁。
如果transaction很大,可能会由于rollback segment达到其最大的extents,或是表空间中已经没有可用于extend的空间给rollback segment了,而导致transaction的失败。
* 在查询操作遇到ORA-01555: snapshot too old (rollback segment too small)的错误时,说明此操作需要为了保持一致读的镜像数据块被其他transaction覆盖了。对此的修复只有增大rollback segments。
5、自动管理undo表空间模式
从9i开始,也已通过将UNDO_MANAGEMENT设置为auto将DB设置为自动管理undo表空间的模式(AUM),如果设置为manual则仍 使用手工的管理(RBU)。当在一个transaction中,第一个DML操作被执行,transaction将被分配到当前undo tablespace中的一个rollback segment上。可以通过参数UNDO_RETENTION设置存放在AUM中的undo信息的数量。
1)AUM的tablespace:
具体创建undo tablespace的方法:create database是使用undo tablespace子句,此时会创建一个名为SYS_UNDOTBS的undo tablespace,在$ORACLE_HOME/dbs下将会生成DBU1<SID>.dbf的文件,并且autoextend=on; 另外可以使用create undo tablespace创建。
2)对于AUM的表空间,可做下面的操作:
alter tablespace tspname
• ADD DATAFILE
• RENAME
• DATAFILE [ONLINE|OFFLINE]
• BEGIN BACKUP
• ENDBACKUP
DBA仍可切换当前使用的undo tablespace,只有一个undo tablespace可以设置为active。
eg:ALTER SYSTEM SET UNDO_TABLESPACE=UNDOTBS2;
当该指令发出,所有新的transaction将被指向新的undo tablespace,当前正在运行的transaction将继续沿用旧的undo tablespace,直到结束。
DBA只能通过drop tablespace命令删除当前非active的undo tablespace,并且其不包含任何未提交的transaction的rollback data。
3)对于自动管理undo tablespace的参数设置:
* UNDO_MANAGEMENT:指明是AUTO或MANUAL
* UNDO_TABLESPACE:指明当前active的undo tablespace。如果在创建是没有undo tablespace可用,则会使用system表空间作为rollback segment的分配空间。
* UNDO_SUPPRESS_ERRORS:此参数主要用于使用SET TRANSACTION USE ROLLBACK命令下
* UNDO_RETENTION:设置存放在AUM中的undo信息的数量。其单位是秒,默认值是900
关于undo retention所需的空间的计算:
undo space = (UNDO_RETENTION * (undo blocks per second*db_block_size) ) + DB_BLOCK_SIZE
可以使用下面的sql进行计算,并设置undo tablespace的大小:
SELECT (RD*(UPS*OVERHEAD) + OVERHEAD) AS “bytes”
FROM (SELECT value AS RD FROM v$parameter where name = ‘undo_retention’),
(SELECT (SUM(UNDOBLKS)/SUM(((end_time-begin_time)*86400))) as UPS FORM v$undostat),
(SELECT value AS Overhead FROM v$parameter where name=’db_block_size’);
4)对自动管理undo tablespace的监控:
通过查看V$UNDOSTAT视图可以完成监控的任务。字段UNDOBLKS显示了undo blocks的分配数量。
1、Locking机制
1)Oracle Server中是自动管理锁的。默认会使用最低的锁级别对数据进行一致性的保护,从而满足最大的并发度。
note:默认的锁机制可以通过ROW_LOCKING改变。默认该值是ALWAYS,它将在DML语句中使用最低级别的锁。另一个可能的值是 INTENT,它将使用更高级别的限制(table level),除了select for update语句,它将使用行级锁。
2)quiesced database:如果Oracle被设置为只有DBA可以访问的状态时,就是quiesced database。
3)锁的种类:
** DML locks:
①表级锁(TM):当修改table data时,被设置,如:INSERT, UPDATE, DELETE, SELECT … FOR UPDATE或LOCK TABLE。此时table将被加锁,避免其他DDL的操作引起transaction之间的冲突。
## 在TM中又可分为两种锁,是由server根据当前其他表锁的加载情况而自动为DML选择加上的。这两种锁具体是:row exclusive(RX),运行其他transaction中的insert、update、delete或其他加行级锁的并发操作在当前同一 table上,但不允许其他手动加载的排他读/写锁;row share(RS),运行SELECT … FOR UPDATE命令时加载的表锁,这只会对避免其他事务手动的对当前table加载锁用于排他的写操作。
## 表锁模式:
(i)手动加载表锁模式使用语句LOCK TABLE table_name IN mode_name MODE; –一般不使用这种明确加锁的方法,只有application要求,才会不得不加较高级别的锁。
(ii)Share(S)锁模式:此类表锁只允许其他transaction发出select … from update的请求,不允许任何对table的修改。隐含式的获得share lock的sql语句中,会包含相应的完整性约束。在9i中,不会申请子表中外键字段的索引约束。
(iii)Share Row Exclusive(SRX):它是比S模式更高的锁模式。它不允许任何其他的DML语句和手动加载的共享锁模式。相应的SQL语句会隐式的获得相应的完整性约束的SRX锁。
(iv)Exclusive(X)锁:这是最高的锁模式,只允许其他对该表的查询请求,拒绝一切对表的任何DML操作和手动锁。
②行级锁(TX):当发出命令INSERT, UPDATE, DELETE, SELECT … FOR UPDATE命令时,会自动为所操作的row对象加TX,从而确保没有其他user同时对同一行进行才操作。
一个DML事务,会同时获得两个锁:共享表级锁和排他行级锁。获得行级锁的每行都返回
③在blocks中的DML锁:加锁的信息只有在transaction被commit或是rollback后才会被清除。而不是在当前事务的下一个请求语句发起时被释放。在blocks header中,Oracle server为每个当前active的transaction保存了一个标识符。在每条row中,会有一个lock byte存储了包含当前transaction的slot的标识符。
** DDL locks:避免对schema对象的定义时,有其他相关的DDL操作进行。
Oracle是通过入队的方式对锁进行维护的,入队机制会记录下面的信息:user等待的locks被其他user占用;users请求的locks的具体类型;users请求的locks的顺序。
可以通过改变参数DML_LOCKS和ENQUEUE_RESOURCES参数来增加可被request的locks。这在Parallel server中是必须的设置。DDL锁的分类有:
①Exclusive DDL Locks:某些DDL语句,如CREATE, ALTER, DROP,必须获得其操作object的排他锁。如果其他user获得了其他任何级别的lock,当前user都不能得到其DDL的排他锁。
②Shared DDL locks:当发起GRANT和CREATE PACKAGE操作时,需要获得相应object的共享DDL lock。该类locks不会阻止类似的DDL语句或是任何DML语句,但会防止其他user对当前引用的object被修改或删除。
③Breakable Parse Locks:保存在library cache中的statement和PL/SQL对象保存了其引用的每个object的breakable parse Lock,直到该statement过期。它用于检验library cache中的相应内容是否因为object的改变而可用。
2、可能引起Locks冲突的原因:
1)使用了不必要的high-level锁
2)长期运行的transaction的存在
3)user没有及时的commit对database的修改
4)使用Oracle instance的application使用了higher locks
3、监控并诊断当前加锁情况的工具
1)如上图所示,其中视图DBA_WAITERS和DBA_BLOCKERS用于进一步查看当前获得或是等待不同table的locks的信息。对此,需要用$ORACLE_HOME/rdbms/admin中的catblock.sql脚本创建。
2)对于v$lock视图来说,当lock tpye为TX时,id1中显示的回滚段的number和slot number;当lock tpye为TM时,id1中显示的是被修改表的object ID。
SELECT owner, object_id, object_name, object_type, v$lock.type FROM dba_objects, v$lock WHERE object_id=v$lock.id1 and object_name=table_name;
3)V$LOCKED_OBJECT视图
XIDUSN:Rollback segment number
OBJECT_ID:ID of the object being modified
SESSION_ID:ID of the session locking the object
ORACLE_USERNAME
LOCKED_MODE
在此视图中,当XIDUSN为0时,则表示当前session正在等他其他已经获得该lock的session释放。
4)关于脚本utllockt.sql
可以使用$ORACLE_HOME/rdbms/admin/utllockt.sql脚本显示当前等待lock的进程继承关系。但使用之前必须用catblock.sql脚本创建视图dba_locks和dba_blockers。
5)如果想要得知哪一行造成了lock冲突,可以查看v$session中的row_wait_block#, row_wait_row#, row_wait_file#, row_wait_obj#四个字的的值。
4、解决locks的冲突方法有:一方面可以请相应的user做commit/rollback;在万不得已的时候,可以kill掉某些user session,从而回滚相应的transaction并释放locks。具体方法如下:
select sid, serial#, username from v$session where type=’USER’;
alter system kill session ’sid,serial#’;
5、死锁:对于Oracle,当其检测到死锁的存在,会rolling back那个检测到死锁的语句,当不是整个transaction的rollback。必要时,需要DBA完成剩下的rollback工作。明确的指明语 句中使用的锁,从而覆盖默认的锁机制,可能容易引起deadlock。
当发生死锁后,server会将deadlock的情况记录到USER_DUMP_DEST目录下的跟踪文件。在分布式transaction中,本地的 deadlock是通过等待关系图(waits for graph)来判断的,全局死锁是通过time-out来判断的。
Oracle进程与files
1、performance guidelines
1)对于吞吐量较大的OLTP应用中,当使用dictionary管理表空间的方法时,由于所有的extent分配时都会要访问dictionary,从而造成了冲突。而使用本地管理表空间的方法避免了这类冲突,从而提高了并发性。
2)在本地管理表空间中,使用自动空间管理方法,用位图记录不同blocks的使用情况。也提高了相应的速度。
3)当创建一个user后,就会分配一块所需的磁盘排序所需临时表空间。这些排序区应该从其他database object中分离开,如果没有给user分配临时表空间,则其所需的排序区域将从system表空间分配。
4)tables和indexes应该被分开存储在不同表空间中。因为indexes和tables经常被同时读写。
5)对于含有LONG或LOB数据类型的tables,应该被分配在不同的表空间中。
6)适当创建多个临时表空间。
2、distributing files across devices:
1)应该将redo log和data file存放在不同的磁盘上,从而在一定程度上降低i/o的压力。
2)对于规模较大的表,如果分不同的区域并发访问也可以提高性能partition。
3)尽可能排除非Oracle Server进程对database file的I/O操作。对此可以使用v$filestat动态的观察。
4)了解应用程序主要的I/O操作,合理安排disk布局,从而提高性能。
3、表空间的作用:其中system表空间主要是用于存放sys创建的data dictionary objects。其他users不可使用该表空间。需要明确的是,packages和database triggers对象等都是data dictionary的一部分。rollback segments应该排他使用其rollback segment。undo segments可以只能存在在undo tablespace中。
4、监控I/O状态的工具
1)v$filestat视图。
select phyrds, phywrts, d.name from v$datafile d, v$filestat f where d.file# = f.file# order by d.name;
2)statspack
5、file striping
1)对OS的striping,通过使用硬件或是软件层次上的striping,可以将同一个文件的不同blocks放在不同的devices上,例如raid技术。提供一定的冗余的同时增大I/O性能的。
此外,设置适当的DB_FILE_MULTIBLOCK_READ参数。
2)手工的striping:可以在多个不同的disk创建tablespace。随后将不同的tables、indexes分配到不同的 tablespace中。此外,可以创建对象时使用MINEXTENTS句柄其值大于1,这样每个extents都将略小于striped data files。也可直接给extents进行分配定位(但我认为这会给管理带来麻烦):alter table tablename allocate extent ( datafile ‘filename’ size 10M);
对于这块争用的问题,使用手动的striping还是比较有效的。
6、对全表扫描的tuning:当对某个disk有较高的读写操作时,多是由于没有适当调节sql的原因。
查看全表扫描的次数:
select name, value form v$sysstat where name like ‘%table scans%‘;
获得的结果中’table scans ( long tables)’的值如果较大,则需要考虑调节sql或是增加适当的indexes。
long tables (长表)指多于4个块的表, short table(短表)指等于或小于4个块的表。
初始化参数DB_FILE_MULTIBLOCK_READ_COUNT决定了在全表扫描时,一次I/O操作中读入的最大的database blocks。它可以改变全表扫描时需要的I/O的次数。该参数的设置应该受到OS限制的I/O的上限的约束。此外此参数还可以在session级别进行 调节。对它的调节可以先查看完成每个表的全表扫描扫描多少blocks。从而从整体上得到较好的设置。要注意的是,对cost-based 优化将会使用该参数评估使用全表扫描的代价,从而判断是否使用全表扫描。
对于全表扫描,Oracle提供了视图v$session_longops来进行监控。
select sid, serial#, opname, to_char(start_time,’HH24:MI:SS’) as starttime, (sofar/totalwork)*100 as percent_complete from v$session_longops;
7、checkpoints
什么是checkpoint?
checkpoint是一个数据库事件,它将已修改的数据从高速缓存刷新到磁盘,并更新控制文件和数据文件。
什么时候发生checkpoint?
我们知道了checkpoint会刷新脏数据,但什么时候会发生checkpoint呢?以下几种情况会触发checkpoint。
1.当发生日志组切换的时候
2.当符合LOG_CHECKPOINT_TIMEOUT,LOG_CHECKPOINT_INTERVAL,fast_start_io_target,fast_start_mttr_target参数设置的时候
3.当运行ALTER SYSTEM SWITCH LOGFILE的时候
4.当运行ALTER SYSTEM CHECKPOINT的时候
5.当运行alter tablespace XXX begin backup,end backup的时候
6.当运行alter tablespace ,datafile offline的时候;
1)它可以引起DBWn的I/O操作,同时会更新datafile header和control file中的scn等信息。
频繁的进行checkpoint可以缩短instance恢复的时间,但是会降低Oracle运行的性能。
在LGWR写redo log文件时,当一个group 被写满时,需要进行log switch是,会先发起一个checkpoint,这就意味着:DBWn会先将所有的与该redo log有关的dirty data blocks写入datafile,随后CKPT会修改datafile header和控制文件。
checkpoint并不会影响其他工作。如果DBWn进程尚未完成checkpoint一个file,此时LGWR需要在此需要这个file时,LGWR不得不等待。
2)对checkpoint性能的监控与调节:
** checkpoint的监控主要是查看alert.log文件。可以将LOG_CHECKPOINT_TO_ALERT参数设置true,从而记录checkpoint的开始结束时间。
** 通过调节online redo log files的大小来降低因日志切换引起的checkpoint;
** 增多redo log 的groups,从而延长LGWR覆盖写的时间,从而避免引起不必要的LGWR等待。
** 具体可调节的参数有:
– FAST_START_IO_TARGET
– LOG_CHECKPOINT_INTERVAL
– LOG_CHECKPOINT_TIMEOUT
– DB_BLOCK_MAX_DIRTY_TARGET
– FAST_START_MTTR_TARGET
如果在OLTP系统中,SGA设置过大,同时checkpoint稀少,可能引起disk冲突。所以也要适当增加checkpoint的频率。
貌似我的理解是除了user发起的alter database checkpoint命令外,主要两类checkpoint,时间间隔型和fast-start类型的。
通过查看v$instance_recovery视图,查看参数设置对DB recovery时间的影响,其中:
RECOVERY_ESTIMATED_IOS:显示了基于fast-start的设置,在recovery时,需要处理的data blocks。
ACTUAL_REDO_BLKS:显示了当前要进行recovery时所需的redo blocks。
TARGET_REDO_BLKS:在recovery时,最大的需要处理的redo blocks。是下面四个指标的最小值。
LOG_FILE_SIZE_REDO_BLKS:在recovery时,为了确保log switch不会等待checkpoint,要处理的redo blocks数量。
LOG_CHKPT_TIMEOUT_REDO_BLKS:在recovery时满足log_checkpoint_timeout,需要处理的redo blocks的数量。
LOG_CHKPT_INTERVAL_REDO_BLKS:在recovery时为了满足log_checkpoint_interval,需要处理的redo blocks的数量。
FAST_START_IO_TARGET_REDO_BLKS:在recovery时为了满足fast_start_io_target,需要处理的redo blocks的数量。
对checkpoint的设置主要围绕的中心就是recovery用时,和它引起的I/O是否会造成性能的问题。
8、redo log的groups和members的设计
一般会把同一组的不同成员放置在不同的disk上,如果在归档模式下,则要考虑将归档日志放到不同的磁盘上。为redo log选择适当的size。同时在一定程度上增加log file的groups,从而避免不必要的等待。
对redo log的监控视图主要有:V$LOGFILE, V$LOG, V$LOG_HISTORY,此外还可结合v$system_event获得的结果。
9、归档日志的设置
当开启归档模式时,可以考虑将不同的groups放在不同的disks上(当然不一定是每个group一个磁盘),同时与归档文件的存放也分离,这样使LGWR进程写的disk和ARCn进程读的disk不在一个上。
可以从视图V$ARCHIVED_LOG上获得动态的归档log文件的信息。V$ARCHIVE_DEST当前归档进程的destinations的状态信息。(由参数log_archive_dest_n设置的destination)
监控诊断ARCn的工具主要是使用视图:V$ARCHIVED_LOG, V$ARCHIVE_PROCESSES, V$ARCHIVE_DEST。
对归档的调节,可以使用LOG_ARCHIVE_MAX_PROCESSES参数指定最大可以创建的归档进程。
如果预计归档工作量较大,可以通过定期运行下面语句来获得其他进程来分担。
alter system archive log all to ‘directory_name’;
注意:9i中,当DBWR_IO_SLAVES参数的设置大于0,Oracle会自动将ARCn的进程数设置为4。(但是我的11g貌似DBWR_IO_SLAVES=0,而ARCn也是4个多啊,大概是设了其他的参数)
设置适当的fast_start_io_target,
1、排序进程:
1)如果排序请求使用的memory不大于参数SORT_AREA_SIZE的设置值,则sort操作在内存中进程。反之,如果超过该值:
①数据将被分隔成更小的pieces,被称作sort runs;每个sorted先被分别的sort。
②server进程会将pieces写入临时表空间segment中;这些segments用于存储中间的sort data。
③sorted pieces被合并从而产生最终结果。如果SORT_AREA_SIZE大小不足以一次merge所有sorted runs,sorted runs的子集会经历几次merge过程。
2)sort area的大小是由SORT_AREA_SIZE设置的,它可动态设置(alter session、alter system deferred),其默认值根据OS的不同而不同。其默认值可以满足一般的OLTP需求,对于DSS应用、批量jobs或是较大操作需要适当的条件。
3)另一个相关的参数是SORT_AREA_RETAINED_SIZE。当sorting操作结束,sort area仍保存了部分等待取出的sorted rows,sort area可以shrink到最小为SORT_AREA_RETAINED_SIZE的大小。该部分memory仍然是被释放到UGA中。其默认值等于 SORT_AREA_SIZE。
4)关于位图索引的初始化参数:
CREATE_BITMAP_AREA_SIZE:此参数是静态的,指明了用于创建位图索引可以分配的memory,默认值是8MB(较大的memory设置会加快bitmap的创建速度,如果位图索引的基数比较小,所需的memory也相对小)
BITMAP_MERGE_AREA_SIZE:该参数也是静态的。默认值是1MB。oracle为索引位图段建立一张位图。在进行位图索引扫描时,需要将扫描到的位图索引排序后与位图合并(Merge
),Oracle会在PGA中开辟一片区域用于排序和合并。它就指定了这片区域的大小。
5)sort Area的新参数:
PGA_AGGREGATE_TARGET:指明了连接instance的所有进程的PGA的总区域大小,大小可从10MB到4000GB。设置时,应该先考虑system总的memory,以及分配给SGA的memory大小,将剩余的部分分配给该参数。它指明了自动sort area管理。
WORKAREA_SIZE_POLICY:该参数可设置为(i)AUTO:只有定义了PGA_AGGREGATE_TARGET参数后才可被设置为 AUTO;(ii)MANUAL:对work areas的Sizing是手动的,是基于*_AREA_SIZE参数设置的值来分配的。如果设置为MANUAL,可能会降低PGA内存的利用率。
6)一般SORT_AREA_SIZE和SORT_AREA_RETAINED_SIZE应该设为相同的大小,除非system memory不足或使用的是Oracle shared server模式。
7)内存的需求:
在single server process中:一个执行计划可能会包含多个排序。例如,一个用sort-merge方式join两个tables并使用order 不用子句的sql,包含了三个sort。对此,在运行order by时,一个SORT_AREA_SIZE大小的memory用于当前的sort;两个SORT_AREA_RETAINED_SIZE大小的 memory用于join sorts。
在parallel query 进程中:假设有2个server,则会使用(SORT_AREA_SIZE*2*并发度)大小的memory,此外如果需要,还要使用 (SORT_AREA_RETAINED_SIZE*并发度*事先做的排序次数)的memory。实验表明分配更大的memory不会对性能有更好的提 高。
2、Tuning sorts
需要注意的问题有:
* 如果数据已经使用索引进行了排序,尽量避免再次排序
* 如果sort操作本身并不大,但是设定的sort area过小使得其不得不进行页面的交换。
* 此外使用大的内存chunks用sort也会造成paging核swapping,从而降低系统性能。
* 避免在频繁分配和收回磁盘上的临时表空间操作
所以应该:尽可能的避免排序操作;尽量使sort操作在内存中完成,减少swapping和paging的操作;尽可能的减少对临时空间的请求。
1)临时表空间的优化:
明确指明sort操作使用的临时表空间,可以有效的避免在分配与收回sort空间时的序列化操作。在临时表空间中,不能包含任何永久的object,在 Oracle Parallel Server中,对于每个instance,会有一个单独的临时表空间。临时表空间的datafile在备份时时不需要备份的。
对于临时sort segment:
* 在第一次需要申请临时表空间的sort操作申请时,sort segment才被创建;
* 在DB被关闭时才被drop,可以用命令行对其进行扩容
* 它也是由extents组成的,可以用于不同的sort 操作
* 在SGA中存在一个叫sort extents pool(SEP)的数据结构,用于管理临时表空间。当进程需要申请sort space时,会先在SEP中查找临时表空间中空闲的extents。
2)需要进行排序的命令请求有:
* 索引的创建:在建立b-tree之前,必须先将索引列进行排序操作;
* order by和group by子句:必须先对该子句使用的字段进行排序;
* distinct关键字:必须为消除重复行先进行排序;
* UNION、INTERSECT或MINUS操作符:server需要为了消除重复rows先对表进行sort。
* 两表之间的sort-merge连接:如果没有相应的索引用于两表的连接,对于等值连接,如果使用此方法join,则先需要对两表进行全表扫描,并分别进行排序,再合并两表。
对于server的排序操作的监控,可以从v$sysstat中查看:
select name, value from v$sysstat where name = ’sorts (rows)’;
可以使用analyze或是dbms_utility.analyze_*等方法对tables、indexes或是cluster进程统计,从而更好的指导CBO,从而产生更好的执行计划。
3)避免使用sort:在任何可能的地方尽量避免使用sort
* 使用nosort关键字创建索引:
默认情况下,在表中创建索引的时候,会对表中的记录进行排序,排序成功后再创建索引。但是当记录比较多的是,这个排序作业会占用比较多的时间,这也就增加了索引建立的时间(排序作业是在索引创建作业中完成)。有时候,我们导入数据的时候,如采用insert into 语句插入数据过程中同时采用Order by子句对索引字段进行了排序。此时如果在索引创建过程中再进行排序的话,就有点脱裤子放屁,多此一举了。为此在重新创建索引时,如果表中的数据已经排好序了(按索引字段排序),那么在创建索引时就不需要为此重新排序。此时在创建索引时,数据库管理员就可以使用NOSORT可选项,告诉数据库系统不需要对 表中当记录进行重新排序了。
采用了这个选项之后,如果表中的记录已经按顺序排列,那么在重新创建索引的时候,就不会重新排序,可以提高索引创建的时间,节省内存中的排序缓存空 间。相反,如果表中的记录是不按索引关键字排序的话,那么此时采用NOSORT关键字的话,系统就会提示错误信息,并拒绝创建索引。所以在使用 NOSORT可选项的时候,数据库管理员尽管放心大胆的使用。因为其实在不能够使用这个选项的时候,数据库也会明确的告知。为此其副作用就比较少,数据库管理员只需要把这个可选项去掉然后重新执行一次即可。不过这里需要注意的是,如果表中的记录比较少的话,那么使用NOSORT选项的效果并不是很明显。
* 使用UNION ALL代替UNION:因为UNION ALL不会消除重复的rows,所以也无需进行sort操作。
* 使用Nested loop join代替sort-merge join
* 在经常使用order by子句的列上创建索引。
* 使用analyze时,只统计所需字段的数据:
ANALYZE … FOR COLUMNS或ANALYZE … FOR ALL INDEXED COLUMNS
* 对于ANALYZE COMPUTE,其统计结果更精确,但是需要进行一定的sort,对此,可以使用ESTIMATE子句来替代大表或cluster中的ANALYZE。
4)诊断工具:
* 在视图v$sysstat中显示的信息中有:
sorts (memory):完全在内存中进行的排序的次数
sorts (disk):请求临时segments的I/O进行sorts的次数
sorts (rows):当前已经进行过的sort的rows的数量
* 在statspack输出的report中也存在上述信息,并计算了部分平均值
* 视图v$sort_segment和v$sort_usage显示了当前临时segment中的使用情况,以及那些user占用了这些临时segment。
@@ 在具体诊断时,可计算磁盘sort和memory sort的比率,它应该小于5%。否则,如果此比率显示了较大的磁盘排序,则需要考虑是否可以增大SORT_AREA_SIZE的设置。
@@ 注意的是:如果增大了sort area,则每个需要sort的进程所占用的memory可能都会增加,在一定程度上影响了OS的memory分配及paging和swapping。所 以当增加了sort_area_size后,考虑是否可以适当减小SORT_RESERVED_AREA_SIZE的值,不过此值的减小,在一定程度上减 少了内存的使用,但也可能附加着造成了I/O的可能性。
6) 监控临时表空间:主要是查看V$SORT_SEGMENT视图:
select tablespace_name, current_users, total_extents, used_extents, extent_hits, max_used_blocks, max_sort_blocks from v$sort_segment;
具体字段的意义如下:
CURRENT_USERS:Number of active users
TOTAL_EXTENTS :Total number of extents
USED_EXTENTS :Extents currently allocated to sorts
EXTENT_HITS: Number of times an unused extent was found in the pool
MAX_USED_BLOCKS: Maximum number of used blocks
MAX_SORT_BLOCKS :Maximum number of blocks used by an individual sort
7)临时表空间的设置:
默认临时表空间的存储参数对于sort segment都是适用的,只是它们有无限的extents。
设置临时表空间的参数时,先要考虑sort_area_size的值。temporary tablespace的initial和next参数应该是sort_area_size的整数倍,并要考虑额外的segment header的空间。将PCTINCREASE设置为0 。
可以为users指定不同的temporary tablespace,并且可以将temp tablespace放在不同的磁盘上,对于查看使用情况,可以看v$sort_usage
select username, tablespace, contents, extents, blocks from v$sort_usage;
此外,还可查看V$TEMPFILE和DBA_TEMP_FILES可以获得temporary tablespace的相关信息。
1、redo log buffer:
当时常遇到较大的事务时,增大log buffer可以减少不必要的log file I/O操作。commit操作将会flush log buffer,频繁的commit可以考虑较小的buffer size。log_buffer最小为64K。
①对redo log buffer的诊断:
** 查看动态视图:v$session_wait查看当前是否正有对log buffer的请求等待。
select sid, event, seconds_in_wait, state from v$session_wait where event = ‘log buffer space%’;
** 计算redo buffer allocation的重试的出现概率,此值应该尽量接近0,不应该大于1%,如果该值不断增加,说明大量对redo log buffer的等待。
select name, value from v$sysstat where name = ‘redo buffer allocation retries’; –显示了user 进程等待log buffer中的space所重试的次数。
select name, value from v$sysstat where name = ‘redo log space requests’;
引起等待的原因可能是由于log buffer过小,或是checkpoint,或是log switching所致。
对此,可以尝试:增大log_buffer的值;或是改善checkpoint或归档进程。
** SECONDS_IN_WAIT值显示的是除了由于log swith以外造成的log buffer等待的时间。它表明redo buffer被写满的速度要大于LGWR写logfile的速度。也可能反映在redo logfile上的I/O存在冲突。
如果怀疑是LGWR的问题,可以继续查看:
@@ 是否存在I/O冲突,是否redo log file存放在分开的快速存储设备上。
@@ 查看日志切换的次数,考虑是否是切换太频繁,是否需要增大log file 的size。
select event, total_waits, time_waited, average_wait from v$system_event where event like ‘log file switch completion%’;
@@ 如果DBWn在尚未完成checkpointing file时,LGWR在此需要相应的文件时,会引起LGWR的等待。对此可以从alert.log文件中查看到相关信息。查看当前是否有未完成的checkpoint事件:
select event, total_waits, time_waited, average_wait from v$system_event where event like ‘log file switch (check%’;
查看参数LOG_CHECKPOINT_INTERVAL和LOG_CHECKPOINT_TIMEOUT是否恰当;并查看redo log file的size和group数。
@@ 如果归档进程不能及时的将redo logfile,也可能会引起LGWR的写入等待。
对此,先确认归档目录没有满,适当增加redo log 的groups。下面的SQL显示了由于归档问题引起的log file switch等待统计。
select event, total_waits, time_waited, average_wait from v$system_evnet where event like ‘log file switch (arch%’;
可以适当增大参数LOG_ARCHIVE_MAX_PROCESSES从而在大负荷量时增多归档进程。
@@ 如果将DB_BLOCK_CHECKSUM设置为true,会因此增加性能上的开支。
此外,尽可能减少redo的操作:
** 直接路径的loading在非归档模式下,是不记录redo log的
** 在归档模式下,直接路径的loading可以使用nologging mode
** 直接insert也可使用nologging mode
** 部分sql可以使用nologging mode
但要明确,即使对table、index、tablespace使用nologging模式,但对于部分操作仍然会产生redo log。如create table … as select; create index … ; alter index … rebuild;
此外,nologging属性对update, delete, 常规路径的insert和各种DDL语句是不会起作用的。(这里貌似对insert添加hint也可以使其nologging)
2、监控Java池内存:select * from v$sgastat where pool = ‘java pool’;
1)用于限制Java session占用的内存的初始参数:
①JAVA_SOFT_SESSIONSPACE_LIMIT:当user session的java命令占用的内存超过该设置,将会发出warning,在跟踪文件做一定的记录,默认为1M。
②JAVA_MAX_SESSIONSPACE_SIZE:当user session的java命令占用内存超过该值,该session将被kill掉,默认为4G。
2)为Java Sizing SGA
①每装载一个class,java引擎会使用8KB shared pool的内存,当装载并处理大的jar files时,可占用50MBshared pool的内存。
②java pool是SGA中的一个组成部分,用于所有存在java code或是在EJE中存在数据的session中。instance startup时,会分配JAVA_POOL_SIZE指定大小的内存。一般会设置为50MB左右,默认是20MB。
3、multiple I/O slave:
4、multiple DBWR 进程
1) 多DBWn进程可以使用DB_WRITER_PROCESSES参数控制。它对于多cpu的SMP系统较有效。但是multiple DBWR与multiple I/O slave是不能同时使用的。
2)对其的调节:
select event, total_waits, time_waited from v$system_event where event=’free buffer waits’;
如果发现上述的SQL的total_waits是较大,可以考虑将增加DBWn进程的数量。
1、Shared Pool的组成
** library cache:存储共享的SQL和PL/SQL代码(解析和编译后的SQL和pl/sql blocks——procedures,Functions,packages,triggers和匿名的pl/sql块)使用最近最少使用算法管理 (LRU),避免语句的重复解析。
** data dictionary cache:保存字典对象的信息
** user global area(UGA):用于在没有设置large pool时存放共享的server connection的信息。保存在Shared模式下session的信息。
当缺少data dictionary cache或library cache的代价比缺少database buffer cache的代价更高,所以对Shared pool的tuning有更高的优先权。在tuning Shared pool时主要关心library cache提高其hit ratio又更重要些。
当Shared pool过小,server为了管理有限的空间,需要消耗更多的cpu,从而引起争用。
Shared pool从整体上可以通过参数shared_pool_size来调节。
2、library cache
在server查找是否有被缓冲的sql时,会先把statement转换为ASCII文本,再进行hash函数的计算。
1)尽可能减少重复解析的次数:尽可能使code扁平化,使用bind variables;可以适当增大library cache的大小,从而减少由于cache不足造成的已经被解析的SQL被换出而引起重新解析的可能;如果在cache中保存的被解析的SQL相关联的 schema object被修改,则该cache中的内容将不可用,所以要尽量避免这样的事件发生。
2)避免library cache的碎片产生:为较大的内存需求保留一定的内存,主要通过shared_pool_reserved_size参数设置;将常用的较大的SQL和 PL/SQL对象pinning到内存中,避免其被换出;为Oracle Shared server设置large pool;尽量少使用较大的匿名blocks,用小的PL/SQL包的方法代替;在Oracle Shared Server中测量共享进程所用的session内存。
3)在v$librarycache中保存了每类数据保存在library cache中的统计信息。其中,三个字段较为重要:gets,显示了相应item总的请求数量;pins,显示了执行的次数;reloads显示了被换出后重载的次数
4)调节library cache的诊断工具:
** v$sgastat
** v$librarycache
eg:sql> select namespace, gethitratio from v$librarycache; –获得命中率,在OLTP中应该高于90%,如果没有达到可以考虑以下方法:
a)提高应用程序代码效率(通过绑定变量,避免SQL的硬解析)
b)增加共享池的大小(增加之前先通过v$sgastat查询是free memory是否足够大,有无增加共享池必要)
** v$sqltext:full SQL text
eg:sql> select sql_text, users_executing, executions, loads from v$sqlarea;
sql> select * from v$sqltext where sql_text like ’select %’;
** v$db_object_cache:缓冲的DB object,包括packages、tables或是SQL中参照的别名
** v$sqlarea:统计了所有的共享cursor和相应的sql的前1000个字符
** 如果重载的比率大于1%,需要考虑增大shared_pool_size。
sql> select sum(pins) “executions”, sum(reloads) “cache misses”, sum(reloads)/sum(pins) from v$librarycache;
在statspack report中,library cache activity (Instance state activity)的内容也显示了此信息:parse count(total、hard、failure)
5)还需要明确的是多次的修改对象,也可能使library cache的内容被标记为invalid,从而造成reload-to-pins值增大。在v$librarycache中的invalidations 字段显示了标记为invalid的次数。注意:analyze语句可用使标记为invalid。
sql>select namespace, pins, reloads, invalidations from v$librarycache;
可以查询v$shared_pool_advice查看oracle建议使用共享内存,也可以通过oracle 的OEM查看共享内存图。
6)与缓冲的执行计划的相关的view:
** 动态性能视图v$sql_plan可用于查看缓冲了的cursor的的执行计划信息,它比plan_table表还多7个字段,两者中的相同字段的值是一 致的。此外在v$sql视图中添加了一个字段plan_hash_value,它为一个hash值,用于匹配执行计划。与v$sqltext、 v$sql_plan、v$sqlarea中的hash_value字段对应。
7)测试applications:对应已经存在的application,先分配一个较大的shared_pool_size,开启应用,计算当前使用的共享内存:
select sum(sharable_mem)
from v$db_object_cache
where type=’PACKAGE’ or type=’PACKAGE BODY’
type = ‘FUNCTION’ or type = ‘PROCEDURE’;
对于相关的SQL语句,需要通过v$SQLAREA查询:
select sum(sharable_mem) from v$sqlarea where executions>5;
此外,也可以假设在每个user每打开一个cursor将增加250 bytes。这可以测试application在高峰期的shared pool的占用:
select sum(250* users_opening) from v$sqlarea;
在测试环境中,可以根据user的多少来估算打开的cursors数量。
select 250 * value bytest_per_user
from v$sesstat s, v$statname n
where s.statistic# = n.statistic# and n.name = ‘opened cursors current’ and s.sid=15;
这样,在理想情况下,application中将占用的library cache大约是上述的总和加上少量的动态SQL。
8)large memory的存在必要性在于满足较大的连续内存的需求,可以通过large_pool_size和 shared_pool_reservered_size来设置。一般会建议将其设置为shared_pool_size 的10%,如果设置为50%或以上,系统将报错。
通过视图v$shared_pool_reserved可以帮助tuning其大小。其中最好的目标是设置使request_misses(由于 large mem不足,通过LRU实现的flush)的长期统计结果接近0。还有一个procedure工具 dbms_shared_pool.aborted_request_threshold,用于限制shared pool在出现ORA-4031之前被flush
对于其调节:如果v$shared_pool_reserved中的request_misses值不为0并且不断增加,需要考虑增加 shared_pool_reserved_size;如果request_misses为0,并且free_memory=>50%,考虑减少 shared_pool_reserved_size;v$shared_pool_reserved中的request_failures(显示了没有 memory用于满足请求)>0并不断增加,可以适当考虑减小shared_pool_reserved_size或增大 shared_pool_size。
9)将large object保存在内存中。
通过下面的语句可以查看在内存中已经cache了那些对象:
select * from v$db_object_cache
where sharable_mem > 10000 and (type=’PACKAGE’ or type = ‘PACKAGE BODY’ or
type = ‘FUNCTION’ or type = ‘PROCEDURE’) and kept = ‘NO’;
需要被pin入内存中的对象主要有:常用的较大的存储对象,如standard、diutil包;编译的常用的triggers;sequences。最 好在开机时就将其pin入内存中(我以为这里可以编写适当的开机trigger)。这样,既是使用命令alter system flush shared_pool时,也不会讲这些object flush掉。
具体pin对象到内存的方法可以使用DBMS_SHARED_POOL.keep存储过程。可以用unkeep方法解除其pin状态。
10)对于匿名pl/sql块:可以先在视图v$sqlarea中找到相应的sql_text,并将其适当的改为packaged Functions来执行。
select sql_text from v$sqlarea where command_type = 47 and length(sql_text) > 500;
此外,可以适当的将这些匿名的PL/SQL blocks pin入内存,如下:
declare /* KEEP_ME */ x number;
begin x := 5;
end;
select address, hash_value from v$sqlarea where command_type = 47 and sql_text like ‘%KEEP_ME%’;
execute dbms_shared_pool.keep(‘address, hash_value’);
11)其他影响library pool的参数
** open_cursors:此参数定义了user进程可分配到的私有SQL area中可以引用的cursor的数量。这些私有SQL area将一直存在,直到cursor被关闭。所以应用中应该及时关闭不用的cursor。
** cursor_space_for_time:其为Boolean值,默认为false,如果设置为true,则共享 SQL areas中将不会把其标识为过期,直到其被关闭。不要将其设置为true,除非v$librarycache中的reload始终保持0时再考虑。当应 用中使用了form或大量的动态SQL,应设置为false。
** session_cached_cursors:此参数用于同一个user会经常解析同一个sql的情况。这会经常出现在form的应用中。当设置了该值,会将关闭的游标的解析仍然cache在内存中,用于后面的软解析。
为了验证设置是否恰当,可以查证v$sesstat中的”session cursor cache hits”和”parse count”的值,如果parses 结果的hits比较小,则考虑增加该值,但是,其增加的开支来自于memory。
3、data dictionary cache及其术语、tuning:
1)了解一些术语:
gets:对某object请求的总次数;
getmisses:显示了data请求造成cache misses的次数
当instance被刚刚startup时,dictionary cache中是空的,所以任何sql都会引起getmisses的增加,但是随着大量data被读入cache,getmisses也会减少。最终,将达到一个稳定的平衡状态。
对data dictionary的调节只能通过间接的调节shared_pool_size。
诊断data dictionary的工具有:
** 视图v$rowcache:主要需要关注的字段是parameter、gets和getmisses
** 在statspack的report中,有相关的内容,其中每个数据字典项的misses的百分比大多数应该< 2%,整个Dictionary Cache应该< 15%。report中的cache usage是cache的实体被使用的次数。
sql>select 1-sum(getmisses)/sum(gets) "dta dic hitration" from v$rowcache;
pct SGA是用于data dictionary cache的SGA的比率。
查看getmisses比gets的总比率的方法:
select parameter, gets, getmisses from v$rowcache where parameter=’dc_objects’ or parameter=’dc_synonyms’;
应尽量将该比率降低到<15%的情况。否则,考虑增加shared_pool_size。
4、UGA和Oracle shared Server
在不同的Oracle Server模式下,UGA的位置也不同,具体如下图:
如果使用的Oracle Shared Server模式,并且没有设置large pool,则user的session data和cursor state将存储在shared pool中,而非dedicated Server模式中的PGA中。sort area和private SQL area包含在session data中。在这种模式的Server中应增加shared_pool_size,PGA将变小。
相关的查询:
select sum(value) || ‘ bytes’ “total session memory” from v$mystat, v$statname
where v$statname.name=’session uga memory’ and v$mystat.statistic#=v$statname.statistic#;
select sum(value) || ‘ bytes’ “total session memory” from v$sesstat, v$statname
where v$statname.name=’session uga memory’ and v$sesstat.statistic#=v$statname.statistic#;
select sum(value) || ‘ bytes’ “total session memory” from v$mystat, v$statname
where v$statname.name=’session uga memory max’ and v$mystat.statistic#=v$statname.statistic#;
5、Large Pool
它是在shared_pool_size之外被分配的,设置它的主要好处在于:
1.它可以用于给I/O服务器进程(dbwr_io_salves,操作系统不支持异步IO,用它来模拟异步)
2.backup、resort进程提供所需的较大的内存,
3.共享服务器的会话内存
4.并行查询消息处理
从而降低shared pool产生碎片的可能及其带来的开支。
它的大小由参数large_pool_size决定。
sql>show parameter large_pool_size
它的使用情况:
sql>select * from v$sgastat where pool='large pool'
1、overview
buffer cache中缓冲了数据文件中的data blocks,是SGA的一部分,可以被所有的进程共享。为了提高性能,Server 进程一次读入多data blocks,DBWn一次写入多个data blocks到data file。
相关的初始化参数有:
DB_CACHE_SIZE:指定默认的buffer pool的size,以bytes为单位。
DB_KEEP_CACHE_SIZE:以bytes为单位,指明keep buffer pool的大小。
DB_RECYCLE_CACHE_SIZE:以bytes为单位,指明recycle buffer pool的大小。
在Oracle8i中,有以下特点:
** buffer cache的大小事由DB_BLOCK_BUFFERS * DB_BLOCK_SIZE决定的;
** 在某个时间点,buffer cache中可能存在同一个data block的多个copies。只有一个是当前实际的block。但是Server为了时间读一致性,结合使用rollback信息,满足不同的查询。
** buffer cache中的blocks通过两个lists进行管理:①LRU list;②dirty list
** buffer cache中的blocks可能有三种状态:①free buffers:其在disk和memory中是一致的,可以被重用;②dirty blocks:disk和memory中的数据不同,只有这些blocks被写入disk,才可被重用;③pinned blocks:当前正在被访问的blocks
2、buffer cache Sizing的参数(9i中)
** 支持多种大小的block,system的block大小仍用db_block_size设置(后面称其为primary block size),但其他tablespace可以有自己不同的block size。
** 默认的与primary block size相关的buffer pool通过db_cache_size设置。DB_KEEP_CACHE_SIZE和DB_RECYCLE_CACHE_SIZE与DB_CACHE_SIZE是独立的。
** 从9i开始对SGA的infrastructure修改变为动态的,可以不必shutdown在startup。
注:由于动态SGA的分配,也引入的新的分配单元granule。可以通过v$buffer_pool监控到buffer cache中granule的分配与回收
1)granule:在9i中,SGA组件分配回收的单位是granule。是一段连续的虚拟内存分配单位。其大小要依赖于对总SGA的估计:如果估计 SGA不足128MB,则设置为4MB,否则设置为16MB。当instance startup时,Server分配granule实体,组成SGA_MAX_SIZE的大小,并分配个SGA的不同组件。最小的SGA中要有3个 granules,分别拥有redo buffer、data buffer cache和shared pool。dba可以通过alter system动态的增加SGA的某个组件的memory大小,但是必须确保有足够的free granules方可成功;memory granules不会被自动释放从而满足其他组件memory增加的需求,可以减小某些组件的memory granules,但是缩减granules必须确保是未使用的,方可成功。在动态添加组件memory时,必须注意:新的cache sizes必须是granule size的整数倍;总的SGA size不可超过MAX_SGA_SIZE;DB_CACHE_SIZE不能设置为0(注意这是9i中,而我现在安装的是11g,情况有所不同啊)
2)动态buffer cache的advisory parameter:通过设置db_cache_advice参数为on,可以提供buffer cache size的合并和预测统计数据,从而辅助DBA调节buffer cache。db_cache_advice的可以设置为:off关闭advisory,并收回相应的memory;ready,关闭advisory, 但保留其memory;on,打开advisory,从而引起一定的cpu和memory开销。为了避免从off过渡到on时引起的ORA-4031 err,需要现将其设置为ready。
3)buffer cache advisory收集的数据信息主要可以通过v$db_cache_advice视图显示
select size_for_estimate, buffers_for_estimate, estd_physical_read_factor,estd_physical_reads
from v$db_cache_advice where name=’DEFAULT’
and block_size = (select value from v$parameter where name = ‘db_block_size’)
and advice_status = ‘ON’;
4)管理database buffer cache
①服务器进程和database buffer cache:当server需要申请一个block时,需要一些步骤:
i)server通过hash函数检查被请求的block是否已经在buffer cache中了。如果被找到了,则将其从LRU list中移动到尾部。这将是逻辑读。如果没被找到,server 进程需要将block从data file中读入。
ii)在从data file中读入时,server 进程将先查找LRU list,找到一个free block。
iii)当查找LRU list时,server 进程同时会将相应的dirty block移动到dirty list中。
iv)如果dirty list超过了其threshold size,server将给DBWn发信号,让其flush在dirty list中的 dirty blocks到data file中。如果server在查找的threshold范围内找不到空闲的block时,DBWn也会受到类似信号,直接将LRU list中的block写入data file。
v)当空闲块被找到之后,server将相应的block读入空闲块。并将其放入LRU list的尾部。
vi)如果block不一致,server将通过当前block和rollback segments重建一个早期版本。
vii)此外,对于DWRn进程,每过3秒,会先将LRU list中的dirty blocks移动到dirty list中,随后将dirty list中的blocks写入data file。
viii)当LGWR进程发起checkpoint signals时,DWRn也会先将LRU list中的dirty blocks移动到dirty list中,随后将dirty list中的blocks写入data file。
ix)当发出命令alter tablespace offline或是进行在线备份时,DBWn也会先将LRU list中的dirty blocks移动到dirty list中,随后将dirty list中的blocks写入data file。
x)在删除object时,DBWn会先将与该object有关的dirty blocks写入磁盘。
xi)在正常的normal、immediate、transactional shutdown时,也会flush data buffer。
2、data buffer size的调节
1)调节的目标是提高data cache中的命中率,从而减少实际的物理I/O。
2)诊断的工具主要是观察cache的命中率(使用v$sysstat和utlbstat.sql与utlestat.sql等)和v$db_cache_advice
select name,value from v$sysstat
where name in (’session logical reads’, ‘physical reads’,
‘physical reads direct’,'physical reads direct (lob)’);
• physical reads: Number of blocks read from disk
• physical reads direct: Number of direct reads, does not require the cache
• physical reads direct (lob): Number of direct reads of large binary objects
• session logical reads: Number of logical read requests
命中率 = 1- (physical reads – physical reads direct – physical reads direct (lob)) / session logical reads
由于v$sysstat中的数据是自instance startup后的累计数据,所以在startup不久就进行此查询获得的结果是没有太大意义的。
v$buffer_pool描述了multiple buffer pools的情况,v$buffer_pool_statistics显示了各个pool的统计情况
select name, physical_reads, db_block_gets,consistent_gets from v$buffer_pool_statistics;
v$bh:描述了保存在cache中的数据blocks
3)tuning:
改变cache的命中率,DBA可以:
①当出现下面的情况时,可以考虑增加buffer cache size:
* cache的命中率不足90%
* 有足够的memory,不会引起额外的缺页现象
* 之前对cache的增加有较好的收效
②如果是由于data的访问特点造成了较低的命中率,可以考虑为不同的blocks使用多buffer pools,并适当的将table配置缓冲到cache中
③此外,对于sorting和parallel reads,如果可以的话,避免其读入cache。
需要注意的是:还需考虑OS的caching的影响。
4)对于命中率主要受到数据访问方式的影响
* 全表扫描
* data和application的设计
* large table的随机访问
* cache的不均匀分布
5)对于cache命中率的评估:
* 如果上一次对data buffer cache的增加没有活动较好的收效,就不要继续对其增加。
* 当查看命中率时,要明确:在全表扫描时遇到的blocks并没有放入到LRU的head部分,所以重复扫描不会造成blocks的缓冲
* 由于设计和应用层造成的重复扫描某个大表时,将会造成性能问题。所以建议尽量在一次读取数据,并适当建立索引。
6)使用multiple buffer pools:当使用multiple buffer pools方法时,objects被分配到那个pool要依靠其访问的方式。有三类buffer pools(我记得在11g中更灵活,不止三类了):
* keep:此类pool用于存放可能被reused的对象。
* recycle:该pool被用于存放reused可能性较小的blocks。
* default:同single buffer cache中的cache是一致的。
主要是通过DB_CACHE_SIZE, DB_KEEP_CACHE_SIZE和DB_RECYCLE_CACHE_SIZE参数设置的。它们都是动态的。在9i中其latches是自动分配 的。在8i中需要用db_block_lru_latches分配,一般是至少每50个blocks分配一个latch。
在使用multiple buffer pools时,可以使用如下sql语句:
CREATE INDEX cust_idx .. STORAGE (BUFFER_POOL KEEP);
ALTER TABLE customer STORAGE (BUFFER_POOL RECYCLE);
ALTER INDEX cust_name_idx STORAGE (BUFFER_POOL KEEP);
当发出alter命令来修改buffer pool时,之前的blocks仍保存在原有的buffer中,新load的才会被cache到新buffer pool中。
因为buffer pool是以segment为单位分配的,有多个segments组成对象就可能被缓冲到不同的buffer pools中。
7)keep buffer pool的使用:在确定keep pool大小时,可以在设计时考虑要把那些object放入该buffer,然后求和即可。具体可以如下:
analyze table hr.countries estimate statistics;
select table_name, blocks from dba_table where owner = ‘HR’ and table_name = ‘COUNTRIES’;
具体可以编写脚本先后对DBA_TABLES, DBA_TAB_PARTITIONS, DBA_INDEXES和DBA_CLUSTERS进行analyze。并根据访问的特性,将部分对象分对象所需要的blocks加总计算。
8)对recycle pool的设置,不要设置过小,以免在事务或SQL还没有被执行完,就已经被换出了。
对其进行监控、并确定其size的工具可以使用v$sysstat中的物理读(physical reads)的统计信息,此外可以使用v$cache视图,它需要在sys下运行catparr.sql脚本进行创建。
v$cache视图从object的角度对buffer pool的blocks的占用进行了统计。其实v$cache是为了Oracle parallel server(OPS)而发布的,在执行catparr.sql时,还创建了其他只在OPS中才有用的视图。它还映射了DB object在datafile中的 extents。当创建了新的object后,需要重新运行该脚本。
在决定recycle pool大小时,可先令recycle pool disable;运行catparr.sql;在DB使用高峰期,运行下述语句计算每个object占用了多少blocks:
select owner#, name, count(*) blocks from v$cache group by owner#, name;
根据不同对象的访问特点,确定哪些应该被放入recycle pool并加总这些对象所占用的blocks,这里我用rcb来表示这个数。分配rcb/4大小的recycle pool。
9)跟踪物理读的方法有很多:用调节工具如Oracle trace manager、sqlplus autotrace或是tkprof运行sql都可以跟踪其执行时的物理读。此外可以查看视图v$sess_io。例如:
select s.username, io.block_gets, io.consistent_gets, io.physical_reads
from v$sess_io io, v$session s where io.sid = s.sid;
10)计算multiple pools下的命中率,可以使用视图v$buffer_pool_statistics
select name, 1-(physical_reads/(db_block_gets+consistent_gets)) “hit_ratio”
from v$buffer_pool_statistics where db_block_gets + consistent_gets > 0;
11)在考虑不同的object使用何种pool时,可从下面的观点出发:
** 对于keep pool:blocks将被频繁使用;segments的大小应该小于default buffer pool大小的10%
** recycle pool:在所属的transaction之外将很少被reused;segment的大小是default buffer pool两倍之多
12)将table caching:如果server通过全表扫描获得数据,blocks将被放到LRUlist的尾部,并可能会很快因缺少free blocks被换出。对此可以选择将整个表cache到list的最近经常使用的部分。具体可以在create table时使用cache关键字,或alter table使用cache,或使用cache的暗示。但是如果将太多的table放入LRU list的most recently used端,可能会使buffer cache非常拥挤。
13)其他cache performance indicators
①select name, value from v$sysstat where name = ‘free buffer inspected’;
如果此获得的等待统计很大,并不断增加需要考虑增加buffer pool。其表示了在查找free buffer是skipped的buffer。之所以skipped,是由于dirty或pinned。
②select event, total_waits from v$system_event where event in (‘free buffer waits’, ‘buffer busy waits’);
除了v$system_event,也可从v$session_wait视图。buffer busy wait表示有多个进程尝试同时访问buffer cache中的部分buffers。通过v$waitstat视图可以查看所有不同buffer被等待统计数据。buffer busy wait中包含的类型有data block、segment header、undo header和undo block。如果在v$waitstat视图中:
* data block(tables或indexes的contention)较大:查看sql是否正确使用了索引;查看是否存在right-hand- indexes的情况(例如索引上的数据是由sequence产生);考虑是否使用segment-space管理或是增加free lists避免多个进程同时向一个block中insert。
* undo header:显示了在回滚段header上冲突:对此如果不使用自动的undo管理,则尝试增加更多的rollback segments。
* undo block:显示了在rollback segment block的冲突:如果不使用自动undo的管理,考虑增大rollback segment的sizes。
* free buffer waits:表示server进程不能找到free buffer了,signal DWRn写入dirty blocks,这个过程引起的等待。对此,可以尝试提升DBWR的效率,另一方面可以考虑是不是buffer cache设置过小了。
引起DBWR高效工作的原因可能是:i/o系统慢;i/o可能在等待某些资源,如latches;buffer cache太小了,造成DBWR需要不断写入脏数据;buffer cache太大了,一个DBWR进程迅速的无法释放足够的buffer。对此,可以进一步查看等待DBWR的session,获知具体的问题。
14)free list:它为每个对象维护一个blocks list用于数据的insert,free lists的数量是可以动态设置的。但是对于单核cpu的系统,使用多free lists的好处不大。调节free list的目的是可以减少insert时对free lists的争用冲突。当使用automatic free space management时,Oracle使用bitmap存储free-list的信息,在数据库上降低了冲突,free lists就可以不用使用了。
** 诊断free list的冲突的存在:
如上,通过v$session_wait获得等待时间具体在等待哪一个block,通过v$waitstat中class为segment header显示了等待freelist的数据,v$system_event视图中event字段为’buffer busy waits’的记录显示freelist的等待的整体信息。我们可以通过dba_segments表查看是那些segments需要增加 freelist。具体的查询语句如下:
select s.segment_name, s.segment_type, s.freelists,
w.wait_time, w.seconds_in_wait, w.state
from dba_segments s, v$session_wait w
where w.event=’buffer busy waits’
and w.p1 = s.header_files and w.p2 = s.header_block;
对freel ist的修改可以使用alter table语句进行动态修改,但是对于自动segment空间管理的模式下是不能对freelist的数量进行修改的。
对于降低buffer busy waits可采取的措施有:
** 对于data blocks:适当改变pctfree或pctused;查看是否有right-hand index;增大initrans的值,降低每个block中存放的记录的数量。
** 对于segment header:使用free lists或增加free lists的数量,使用free list groups。
** 对free list blocks:增加更多的free lists。(在Oracle Parallel Server中,应该确保每个instance有自己的free list group)
15)自动管理空闲空间。从9i开始,可以使用位图对空闲和使用的blocks使用自动空间管理,与free list相比,性能更好。它只能在创建tablespace时指明,此后,建立在该表空间上的所有segment都将以自动空间管理方式管理。
create tablespace tsp datafile ‘/path/datafile.dbf’ size nM
extent management local segment space management auto;