ITPub博客

首页 > Linux操作系统 > Linux操作系统 > Oracle 9i性能调整 [ZT]

Oracle 9i性能调整 [ZT]

原创 Linux操作系统 作者:gjm008 时间:2008-12-25 08:55:18 0 删除 编辑

Oracle 9i性能调整
/* *
作者:欧朝敬
QQ:35712069
手机:13873195792
请转载者不要更改原版内容
 */


1、设置合适的SGA
  常常有人抱怨服务器硬件很好,但是Oracle就是很慢。很可能是内存分配不合理造成的。
  (1)假设
内存有512M,这通常是小型应用。建议Oracle的SGA大约240M,其中:共享池(SHARED_POOL_SIZE)可以设置60M到80M,
根据实际的用户数、查询等来定。数据块缓冲区可以大致分配120M-150M,8i下需要设置
DB_BLOCK_BUFFERS,DB_BLOCK_BUFFER*DB_BLOCK_SIZE等于数据块缓冲区大小。9i
下的数据缓冲区可以用db_cache_size来直接分配。
  (2)假设内存有1G,Oracle 的SGA可以考虑分配500M:共享池分配100M到150M,数据缓冲区分配300M到400M。
  (3)内存2G,SGA可以考虑分配1.2G,共享池300M到500M,剩下的给数据块缓冲区。
(4)
内存2G以上:共享池300M到500M就足够啦,再多也没有太大帮助;(Biti_rainy有专述)数据缓冲区是尽可能的大,但是一定要注意两个问
题:一是要给操作系统和其他应用留够内存,二是对于32位的操作系统,Oracle的SGA有1.75G的限制。有的32位操作系统上可以突破这个限制,
方法还请看Biti的大作吧。
建议在设置参数的同时,init 中使用 lock_sga ,在不同的平台上可能有不同的方式,使得SGA 锁定在物理内存中而不被放入 SWAP 中,这样对效率有好处。
lock_sga = true 的问题

于几乎所有的操作系统都支持虚拟内存,所以即使我们使用的内存小于物理内存,也不能避免操作系统将SGA
换到虚拟内存(SWAP)。所以我们可以尝试使得SGA
锁定在物理内存中不被换到虚拟内存中,这样减少页面的换入和换出,从而提高性能。但在这里遗憾的是,windows 是无法避免这种情况的。
WINDOWS
不能设置lock_sga=true(一个根据平台而定的参数, 如果该参数为 TRUE, 将把所有 SGA 页装载到内存中,
以便使该例程迅速达到最佳性能状态。这将增加例程启动和用户登录的时间,
但在内存充足的系统上能减少缺页故障的出现。),可以通过设置pre_page_sga=true,使得数据库启动的时候就把所有内存页装载,这样可能起
到一定的作用。
警告:
当你把DB_CACHE_ADVICE设置为ON(默认值)时,Oracle会从共享的池中“窃取”RAM页面,这往往严重影响到了库cache。例如,如果设置DB_CACHE_SIZE为500m,Oracle就会从共享池中窃取相当多数量的RAM空间。
为了避免这个问题,我们应该在INIT.ORA文件中把DBA设置为DB_CACHE_ADVICE=READY。这样,Oracle会在数据库启动时预分配RAM内存。
SGA的各个组成部分
事实上,通常我们更习惯通过直观的公式化来表达这样的问题:
OS
使用内存+SGA+并发执行进程数(使用Select Value From V$parameter Where Name Like
'processes%'查看其值,
session默认为1.1*processes+5)*(sort_area_size+hash_ara_size+2M) <
0.7*总内存 (公式是死的,系统是活的,实际应用的调整不必框公式,这不过是一个参考建议)
shared_pool_size共享池 + data buffer缓冲区高速缓存 +large_pool_size 大型池+ java_pool_size Java池=SGA
并发执行进程数*(sort_area_size+hash_ara_size+2M) =PGA(在Oracle9i中)


可以看出,设置SGA时基本上应该掌握的原则是:
    data buffer 一般可以尽可能的大
    shared_pool_size 应该适度
    log buffer 在 1MB 以内就可以了


还有2 个重要参数我们需要注意:
sort_area_size
hash_area_size
这两个参数在非MTS 下都是属于PGA ,不属于SGA。它是为每个session 单独分配的,在我们的服务器上除了OS + SGA,一定要考虑这两部分。


一般的内存分配原则:
联机事物处理OLTP:SGA :65%;PGA:15%;OS:20%
数据仓库和决策支持DSS:SGA:30%;PGA:50%;OS:20%
另一种分配方式:SGA:50%;PGA:35%;OS:15%
本文中的分配方式:SGA:50%;PGA:30%;OS:20%
其中SGA中的分配方式:
Buffer Cache:80% ;Share Pool:15% ;Other:5%或
Buffer Cache:80% ;Share Pool:12% ;Other:8%


例如:2g的windows的平台,os 300m,sag 1.2g,  pga 500m
原则:SGA+PGA+OS使用内存<总物理RAM
A、如果512M RAM  建议 shared_pool_size = 50M, data buffer = 200M
B、如果1G RAM   建议 shared_pool_size = 100M , data buffer = 400M
C、如果2G RAM   建议 shared_pool_size = 200M , data buffer= 800M


假定oracle是 32 bit ,服务器RAM大于2G ,注意你的PGA的情况,,则建议
再具体化,如果512M RAM 建议 shared_pool_size = 50M, data buffer = 200M
如果1G RAM shared_pool_size = 100M , data buffer = 500M
如果2G RAM shared_pool_size = 150M ,data buffer = 1.2G
物理内存再大已经跟参数没有关系了
假定64 bit ORACLE
内存4G  shared_pool_size = 200M , data buffer = 2.5G
内存8G  shared_pool_size = 300M , data buffer = 5G
内存 12G shared_pool_size = 300M-----800M , data buffer = 8G



SQL> select * from v$sga;
NAME                      VALUE
--------------------              ----------
Fixed Size                   104936
Variable Size              823164928
Database Buffers          1073741824
Redo Buffers                 172032
或者
SQL> show sga
Total System Global Area   1897183720 bytes
Fixed Size                   104936 bytes
Variable Size              823164928 bytes
Database Buffers          1073741824 bytes
Redo Buffers                 172032 bytes


Fixed Size
        oracle 的不同平台和不同版本下可能不一样,但对于确定环境是一个固定的值,里面存储了SGA 各部分组件的信息,可以看作引导建立SGA的区域。
Variable Size
        包含了shared_pool_size、java_pool_size、large_pool_size 等内存设置
Database Buffers
       
指数据缓冲区,在8i
中包含db_block_buffer*db_block_size、buffer_pool_keep、buffer_pool_recycle
三部分内存。在9i 中包含db_cache_size、db_keep_cache_size、db_recycle_cache_size、
db_nk_cache_size。
Redo Buffers
      
指日志缓冲区,log_buffer。在这里要额外说明一点的是,对于v$parameter、v$sgastat、v$sga查询值可能不一样。v$
parameter 里面的值,是指用户在初始化参数文件里面设置的值,v$sgastat是oracle
实际分配的日志缓冲区大小(因为缓冲区的分配值实际上是离散的,也不是以block 为最小单位进行分配的),v$sga
里面查询的值,是在oracle 分配了日志缓冲区后,为了保护日志缓冲区,设置了一些保护页,通常我们会发现保护页大小是8k(不同环境可能不一样)。
对于一个Oracle应用系统来说,SGA决不是越大越好,这就需要寻找一个系统优化的平衡点。

于数据库有多少并发连接,这实际上关系到PGA
的大小(共享服务器模式(MTS)下还有large_pool_size)。事实上这个问题应该说还跟OLTP 类型或者OLAP
类型相关。对于OLTP类型oracle 倾向于可使用MTS,对于OLAP 类型使用独立模式,同时OLAP
还可能涉及到大量的排序操作的查询,这些都影响到我们内存的使用。那么所有的问题综合起来,实际上主要反映在UGA(用户全局区)的大小上。UGA主要包
含以下部分内存设置
SQL> show parameters area_size
NAME                                 TYPE    VALUE
------------------------------------               -------     --------
bitmap_merge_area_size                   integer    1048576
create_bitmap_area_size                   integer    8388608
hash_area_size                           integer     131072
sort_area_size                            integer     65536
SQL>
在这部分内存中我们最关注的通常是sort_area_size,这是当查询需要排序的时候,数据库会话将使用这部分内存进行排序,当内存大小不足的时候,使用临时表空间进行磁盘排序。由于磁盘排序效率和内存排序效率相差好几个数量级,所以这个参数的设置很重要。

出现大量排序时的磁盘I/O操作时,可以考虑增加sort_area_size的值。sort_area_size是Oracle用于一次排序所需的最大
内存数,在排序结束但是结果列返回之前,Oracle会释放sort_area_size大小的内存,但是会保留
sort_area_retained_size大小的内存,知道最后一行结果列返回以后,才释放所有的内存。
会导致排序的语句有 SELECT DISTINCT , MINUS , INTERSECT , UNION 和 min()、max()、count() 操作;而不会导致排序的语句有 UPDATE , 带BETWEEN子句的SELECT 等等。
排序是一项花销很大的操作,而且对性能的影响程度也较大,因此使大部分排序在内存中完成,而不是在磁盘上进行,这是至关重要的。
识别排序量的大小,就是要确定内存中排序的量和磁盘上排序的量,可用如下语句查询:
SELECT NAME,VALUE FROM V$SYSSTAT WHERE Name IN ('sorts (memory)', 'sorts (disk)');

中“sorts(memory)”选项表示不需要磁盘I/O,选项“sorts(disk)”
表示需要磁盘I/O。如果用户认为在磁盘上的排序意义较大,可以增加init.ora文件SORT_AREA_SIZE参数的设置值。一般不调整该参数,
除非排序量很大时才调整。
这四个参数都是针对会话进行设置的,是单个会话使用的内存的大小,而不是整个数据库使用的。偶尔会看见有人误解了这个参
数以为是整个数据库使用的大小,这是极其严重的错误。假如设置了MTS,则UGA(用户全局区)被分配在large_pool_size,也就是说放在了
共享内存里面,不同进程(线程)之间可以共享这部分内存。
在这个基础上,我们假设数据库存在并发执行server process 为100
个,根据上面我们4 个参数在oracle8.1.7 下的默认值,我们来计算独立模式下PGA
的大致大小。由于会话并不会经常使用create_bitmap_area_size
、bitmap_merge_area_size,所以我们通常不对四个参数求和。在考虑到除这四个参数外会话所保存的变量、堆栈等信息,我们估计为
2M,则200 个进程最大可能使用200M 的PGA。
现在,根据上面这些假定,我们来看SGA 实际能达到多少内存。在1G
的内存的服务器上,我们能分配给SGA 的内存大约为400—500M。若是2G 的内存,大约可以分到1G的内存给SGA,8G
的内存可以分到5G的内存给SGA。当然我们这里是以默认的排序部分内存sort_area_size=64k进行衡量的,假如我们需要调大该参数和
hash_area_size等参数,然后我们应该根据并发的进程的数量,来衡量考虑这个问题。


各个参数的设置
如果SGA_MAX_SIZE>128M建议以下各值都是16的整数倍,SGA_MAX_SIZE<128M,则是4的整数倍。
那么SGA中的各个参数具体应该按照什么样的原则来设置呢,下面进行讨论:
log_buffer
对于日志缓冲区的大小设置,通常我觉得没有过多的建议,因为参考LGWR写的触发条件之后,我们会发现通常超过3M意义不是很大。作为一个正式系统,可能考虑先设置这部分为log_buffer=1—3M 大小,然后针对具体情况再调整。
large_pool_size大型池

于大缓冲池的设置,如果不设置MTS,通常在 RMAN 、OPQ 会使用到,但是在10M --50M 应该差不多了。假如设置 MTS,则由于
UGA (用户全局区)放到large_pool_size的缘故,这个时候依据 session 最大数量和 sort_ares_size
等参数设置,必须增大large_pool_size 的设置,可以考虑为 session * (sort_area_size +
2M)。这里要提醒一点,不是必须使用MTS,我们都不主张使用MTS,尤其同时在线用户数小于500 的情况下。
java_pool_size Java池
假如数据库没有使用JAVA,我们通常认为保留10—20M大小足够了。事实上可以更少,甚至最少只需要32k,但具体跟安装数据库的时候的组件相关(比如http server)。
shared_pool_size共享池

是迄今为止最具有争议的一部分内存设置。按照很多文档的描述,这部分内容应该几乎和数据缓冲区差不多大小。但实际上情况却不是这样的。首先我们要考究一个
问题,那就是这部分内存的作用,它是为了缓存已经被解析过的SQL,而使其能被重用,不再解析。这样做的原因是因为,对于一个新的SQL
(shared_pool
里面不存在已经解析的可用的相同的SQL),数据库将执行硬解析,这是一个很消耗资源的过程。而若已经存在,则进行的仅仅是软分析(在共享池中寻找相同
SQL),这样消耗的资源大大减少。所以我们期望能多共享一些SQL,并且如果该参数设置不够大,经常会出现ora-04031错误,表示为了解析新的
SQL,没有可用的足够大的连续空闲空间,这样自然我们期望该参数能大一些。但是该参数的增大,却也有负面的影响,因为需要维护共享的结构,内存的增大也
会使得SQL 的老化的代价更高,带来大量的管理的开销,所有这些可能会导致CPU 的严重问题。
在一个充分使用绑定变量的比较大的系统
中,shared_pool_size 的开销通常应该维持在300M 以内。除非系统使用了大量的存储过程、函数、包,比如oracle erp
这样的应用,可能会达到500M甚至更高。于是我们假定一个1G内存的系统,可能考虑设置该参数为100M,2G 的系统考虑设置为150M,8G
的系统可以考虑设置为200—300M。
对于一个没有充分使用或者没有使用绑定变量系统,这可能给我们带来一个严重的问题。所谓没有使用bind var 的SQL,我们称为Literal SQL。也就是比如这样的两句SQL我们认为是不同的SQL,需要进行2 次硬解析:
select * from EMP where name = ‘TOM’;
select * from EMP where name = ‘JERRY’;

如把 ’TOM’ 和 ’JERRY’ 换做变量V,那就是使用了bind var,我们可以认为是同样的SQL 从而能很好地共享。共享SQL
本来就是shared_pool_size 这部分内存存在的本意,oracle的目的也在于此,而我们不使用bind var
就是违背了oracle
的初衷,这样将给我们的系统带来严重的问题。当然,如果通过在操作系统监控,没有发现严重的cpu问题,我们如果发现该共享池命中率不高可以适当的增加
shred_pool_size。但是通常我们不主张这部分内存超过800M(特殊情况下可以更大)。
事实上,可能的话我们甚至要想办法避免软分析,这在不同的程序语言中实现方式有差异。我们也可能通过设置session_cached_cursors 参数来获得帮助(这将增大PGA)
关于使用绑定变量的话题,在下面的应用优化中继续讨论。
Data buffer缓冲区高速缓存

在我们来谈数据缓冲区,在确定了SGA
的大小并分配完了前面部分的内存后,其余的,都分配给这部分内存。通常,在允许的情况下,我们都尝试使得这部分内存更大。这部分内存的作用主要是缓存
DB BLOCK,减少甚至避免从磁盘上获取数据,在8i中通常是由db_block_buffers*db_block_size
来决定大小的。如果我们设置了buffer_pool_keep 和buffer_pool_recycle,则应该加上后面这两部分内存的大小。


32bit 与 64bit 对SGA的影响
为什么在上面SGA大小设置的经验规则中要分 32bit Oracle 和 64bit
Oracle
呢,是因为这关系到SGA大小的上限问题。在32bit的数据库下,通常oracle只能使用不超过1.7G的内存,即使我们拥有12G的内存,但是我们
却只能使用1.7G,这是一个莫大的遗憾。假如我们安装64bit的数据库,我们就可以使用很大的内存,几乎不可能达到上限。但是64bit
的数据库必须安装在64bit 的操作系统上,可惜目前windows上只能安装32bit的数据库


9i中相关参数的变化
oracle的版本的更新,总是伴随着参数的变化,并且越来越趋向于使得参数的设置更简单,因为复杂的参数设置使得
DBA们经常焦头烂额。关于内存这部分的变化,我们可以考察下面的参数。事实上在9i中数据库本身可以给出一组适合当前运行系统的SGA相关部分的参数调
整值(参考V$
DB_CACHE_ADVICE、V$SHARED_POOL_ADVICE),关于PGA也有相关视图V$PGA_TARGET_ADVICE 等。
Data buffer
9i
中保留了8i中的参数,如设置了新的参数,则忽略旧的参数。9i中用db_cache_size来取代8i中的db_block_buffers
*db_block_size, 用db_keep_cache_size 取代buffer_pool_keep,
用db_recycle_cache_size 取代buffer_pool_recycle;这里要注意9i
中设置的是实际的缓存大小而不再是块的数量。另外9i新增加了db_nk_cache_size,这是为了支持在同一个数据库中使用不同的块大小而设置
的。对于不同的表空间,可以定义不同的数据块的大小,而缓冲区的定义则依靠该参数的支持。其中n 可以为2、4、6、8、16
等不同的值。在这里顺便提及的一个参数就是db_block_lru_latches,该参数在9i中已经成为了保留参数,不推荐手工设置。
PGA
在9i
里面这部分也有了很大的变化。在独立模式下,9i已经不再主张使用原来的UGA相关的参数设置,而代之以新的参数。假如
workarea_size_policy=AUTO(缺省),则所有的会话的UGA 共用一大块内存,该内存由
pga_aggregate_target 设置。在我们根据前面介绍的方法评估了所有进程可能使用的最大PGA
内存之后,我们可以通过在初始化参数中设置这个参数,从而不再关心其他 ”*_area_size” 参数。
在Oracle 9i,PGA 被逻辑地分成两个部分:
可调整区域,即SQL工作区,等等
不可调整区域,比如说sort area等等
为了调整PGA,我们需要介绍两个新的参数:WORKAREA_SIZE_POLICY 和 PGA_AGGREGATE_TARGET。
WORKAREA_SIZE_POLICY
的值可以是AUTO 或者
MANUAL,该参数意味着是使用以前的方法管理PGA的使用(如,sort_area_size,hash_area_size等等),还是使用新的方
法来管理PGA的使用。如果没有设置参数PGA_AGGREGATE_TARGET,则WORKAREA_SIZE_POLICY的缺省值是
MANUAL。
PGA_AGGREGATE_TARGET参数意味着可以划分到SGA中的最大的数量的内存(也就是Oracle想在所有会话中间
分配的会话PGA内存的总量),它包括所有session的可调整和不可调整的部分,这个参数没有缺省值,当我们将
WORKAREA_SIZE_POLICY 设置为 AUTO之前,必须先设置PGA_AGGREGATE_TARGET参数。
我们可以通过下面的方式查看PGA的使用:
SQL>SELECT SUM(PGA_USED_MEM), SUM(PGA_ALLOC_MEM), SUM(PGA_MAX_MEM) FROM V$PROCESS;
SUM(PGA_USED_MEM) SUM(PGA_ALLOC_MEM) SUM(PGA_MAX_MEM)
----------------- ------------------ ----------------
         14569292           28619756         28619756
其中:
PGA_USED_MEM:该进程当前使用的PGA大小;
    PGA_ALLOC_MEM:当前分配给该进程的总的PGA大小;
    PGA_MAX_MEM:曾经分配给该进程的最大的PGA大小
PGA参考值的设置为
select min(pga_target_for_estimate)  PGA的值 from v$pga_target_advice where estd_pga_cache_hit_percentage>95 /*pga高速缓存命中率*/


SGA_MAX_SIZE
在9i中若设置了SGA_MAX_SIZE,则在总和小于等于这个值内,可以动态的调整数据缓冲区和共享池的大小


库缓冲区的调整
库缓冲区中包含私用和共享SQL和PL/SQL区,通过比较库缓冲区的命中率决定它的大小。要调整库缓冲区,必须首先了解该
库缓冲区的活动情况,库缓冲区的活动统计信息保留在动态性能表v$librarycache数据字典中,可通过查询该表来了解其活动情况,以决定如何调
整。
  SELECT SUM(PINS), SUM(RELOADS),SUM(RELOADS)/SUM(PINS) FROM V$LIBRARYCACHE;
Pins
列给出SQL语句,PL/SQL块及被访问对象定义的总次数;Reloads列给出SQL
和PL/SQL块的隐式分析或对象定义重装载时在库程序缓冲区中发生的错误。如果sum(reloads)/sum(pins)
≈0,则库缓冲区的命中率合适;若sum(reloads)/sum(pins)>1, 则需调整初始化参数
shared_pool_size来重新调整分配给共享池的内存量。


数据字典缓冲区的调整
数据字典缓冲区包含了有关数据库的结构、用户、实体信息。数据字典的命中率,对系统性能影响极大。数据字典缓冲区的使用情况记录在动态性能表v$librarycache中,可通过查询该表来了解其活动情况,以决定如何调整。
  SELECT SUM(GETS), SUM(GETMISSES),SUM(GETMISSES)/SUM(GETS) FROM V$ROWCACHE;
 
 Gets列是对相应项请求次数的统计;Getmisses
列是引起缓冲区出错的数据的请求次数。对于频繁访问的数据字典缓冲区,sum(getmisses)/sum(gets)<10%~15%。若大于
此百分数,则应考虑增加数据字典缓冲区的容量,即需调整初始化参数shared_pool_size来重新调整分配给共享池的内存量。


缓冲区高速缓存的调整
用户进程所存取的所有数据都是经过缓冲区高速缓存来存取,所以该部分的命中率,对性能至关重要。缓冲区高速缓存的使用情况记录在动态性能表v$sysstat中,可通过查询该表来了解其活动情况,以决定如何调整。
SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME IN ('db block gets', 'consistent gets', 'physical reads');
db
block gets(数据库块获取)和consistent gets(一致性获取)的值是请求数据缓冲区中读的总次数(逻辑读)。physical
reads的值是请求数据时引起从盘中读文件的次数(物理读)。从缓冲区高速缓存中读的可能性的高低称为缓冲区的命中率,计算公式:
  Hit Ratio=1-(physical reds/(dbblock gets+consistent gets))
 
 如果Hit
Ratio<60%~70%,则应增大db_block_buffers的参数值。db_block_buffers可以调整分配给缓冲区高速缓存
的内存量,即db_block_buffers可设置分配缓冲区高速缓存的数据块的个数。缓冲区高速缓存的总字节数=db_block_buffers的
值*db_block_size的值。 db_block_size 的值表示数据块大小的字节数,可查询 v$parameter 表:
select name,value from v$parameter where name='db_block_size';
直接计算命中率使用以下语句
SELECT
SUM(DECODE(NAME, 'physical reads', VALUE, 0)) "physical reads",
SUM(DECODE(NAME, 'db block gets', VALUE, 0)) "db block gets",
SUM(DECODE(NAME,'consistent gets', VALUE,0)) "consistent gets",(1 -
SUM(DECODE(NAME, 'physical reads', VALUE, 0)) /(SUM(DECODE(NAME, 'db
block gets', VALUE, 0)) + SUM(DECODE(NAME, 'consistent gets', VALUE,
0))) )*100 "命中率%" FROM (SELECT 1 NO, NAME, VALUE FROM V$SYSSTAT WHERE
NAME IN ('db block gets', 'consistent gets', 'physical reads')) A GROUP
BY A.NO
  在修改了上述数据库的初始化参数以后,必须先关闭数据库,在重新启动数据库后才能使新的设置起作用。


2、选用适合的ORACLE优化器
ORACLE的优化器共有3种:
a. RULE (基于规则) b. COST (基于成本) c. CHOOSE (选择性)
设置缺省的优化器,可以通过对init.ora文件中OPTIMIZER_MODE参数的各种声明,如RULE,COST,CHOOSE,ALL_ROWS,FIRST_ROWS . 你当然也在SQL句级或是会话(session)级对其进行覆盖.
为了使用基于成本的优化器(CBO,Cost-BasedOptimizer),你必须经常运行analyze命令,以增加数据库中的对象统计信息(objectstatistics)的准确性.
如果数据库的优化器模式设置为选择性(CHOOSE),那么实际的优化器模式将和是否运行过analyze命令有关. 如果table已经被analyze过, 优化器模式将自动成为CBO , 反之,数据库将采用RULE形式的优化器.
Oracle
默认优化模式是CHOOSE,在这种情况下,如果表没有经过分析,经常导致查询使用全表扫描,而不使用索引。这通常导致磁盘I/O太多,而导致查询很慢。
如果没有使用执行计划稳定性,则应该把表和索引都分析一下,这样可能直接会使查询速度大幅提升。分析表命令可以用ANALYZE TABLE
分析索引可以用ANALYZE
INDEX命令。对于少于100万的表,可以考虑分析整个表,对于很大的表,可以按百分比来分析,但是百分比不能过低,否则生成的统计信息可能不准确。可
以通过DBA_TABLES字典的LAST_ANALYZED列来查看表是否经过分析或分析时间,索引可以通过DBA_INDEXES字典的
LAST_ANALYZED列。CBO是ORACLE推荐使用的优化方式,要想使用好CBO,使SQL语句发挥最大效能,必须保证统计数据的及时性。统计
信息的生成可以有完全计算法和抽样估算法。
ANALYZE_SCHEMA用于对某个用户拥有的所有TABLE,INDEX和CLUSTER的分析统计。ANALYZE_DATABASE用于对整个数据库进行分析统计。
例:EXECUTE DBMS_UTILITY.ANALYZE_SCHEMA('SCOTT','ESTIMATE',null,100);其中SCOTT改成相应的用户名,100%的抽样百分比。(最好用下面两种方式)
或exec dbms_stats.gather_schema_stats(ownname => 'DONGAN',estimate_percent =>100, cascade=> TRUE);估算统计信息(100%分析),连索引一起分析
或exec dbms_stats.gather_schema_stats(ownname => 'DONGAN', cascade =>true);由计算统计,加cascade =>true则连索引一起分析,否则只分析表
一般现在使用dbms_stats取代dbms_utility包进行数据库统计信息的分析。
以下两个参数对于CBO的巨大影响:
OPTIMIZER_INDEX_CACHING

整基于成本的优化程序的假定值,这个初始化参数代表一个百分比,取值范围在0到99之间.缺省值是0,代表当CBO使用索引访问数据时,在内存中发现数据
的比率是0%,这意味着通过索引访问数据将需要产生物理读取,代价昂贵。如果使用缺省设置,Oracle评估成本的时候,很多时候就会错误的选择全表扫
描。
OPTIMIZER_INDEX_COST_ADJ
这个初始化参数代表一个百分比,取值范围在1到10000之间.
该参数表示索引扫描和全表扫描成本的表较。缺省值100表示索引扫描成本等于全表扫描。optimizer_index_cost_adj参数值设小,使系统倾向于使用索引
这些参数对于CBO的执行具有重大影响,其缺省值对于数据库来说通常需要调整。
一般来说对于OPTIMIZER_INDEX_CACHING可以设置为90左右
对于大多数OLTP系统,OPTIMIZER_INDEX_COST_ADJ可以设置在10到50之间。对于数据仓库和DSS系统,可能不能简单的把OPTIMIZER_INDEX_COST_ADJ设置为50,通常我们需要反复调整取得一个合理值.
OPTIMIZER_MAX_PERMUTATIONS

于多表连接查询,如果采用基于成本优化(CBO),ORACLE会计算出很多种运行方案,从中选择出最优方案。这个参数就是设置oracle究竟从多少种
方案来选择最优。如果设置太大,那么计算最优方案过程也是时间比较长的。Oracle805和8i默认是80000,8建议改成2000。对于9i,已经
默认是2000了。
影响全表扫描的参数
 DB_FILE_MULTIBLOCK_READ_COUNT
 在涉及一个完全连续扫描的一次 I/O 操作过程中读取的块的最大数量

DB_FILE_MULTIBLOCK_READ_COUNT(一般为操作系统I/O大小除以DB_BLOCK_SIZE的值,现操作系统的I/O一般为
64KB,有的达到了1M)改大时(DB_FILE_MULTIBLOCK_READ_COUNT*DB_BLOCK_SIZE为操作系统I/O的整数
倍),或查看执行计划表,明明有索引而不使用索引时,OPTIMIZER_INDEX_COST_ADJ建议改成10。
3、访问Table的方式
ORACLE 采用两种访问表中记录的方式:
a. 全表扫描
全表扫描就是顺序地访问表中每条记录. ORACLE采用一次读入多个数据块(database block)的方式优化全表扫描.
b. 通过ROWID访问表

可以采用基于ROWID的访问方式情况,提高访问表的效率, ,
ROWID包含了表中记录的物理位置信息..ORACLE采用索引(INDEX)实现了数据和存放数据的物理位置(ROWID)之间的联系.
通常索引提供了快速访问ROWID的方法,因此那些基于索引列的查询就可以得到性能上的提高.


4、共享SQL语句
为了不重复解析相同的SQL语句,在第一次解析之后,
ORACLE将SQL语句存放在内存中.这块位于系统全局区域SGA(system global area)的共享池(shared buffer
pool)中的内存可以被所有的数据库用户共享. 因此,当你执行一个SQL语句(有时被称为一个游标)时,如果它和之前的执行过的语句完全相同,
ORACLE就能很快获得已经被解析的语句以及最好的执行路径.
ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用.可惜的是ORACLE只对简单的表提供高速缓冲(cache
buffering) ,这个功能并不适用于多表连接查询.
数据库管理员必须在init.ora中为这个区域设置合适的参数,当这个内存区域越
大,就可以保留更多的语句,当然被共享的可能性也就越大了.当你向ORACLE
提交一个SQL语句,ORACLE会首先在这块内存中查找相同的语句.这里需要注明的是,ORACLE对两者采取的是一种严格匹配,要达成共享,SQL语
句必须完全相同(包括空格,换行等).
共享的语句必须满足三个条件:
A. 字符级的比较: 当前被执行的语句和共享池中的语句必须完全相同. 例如:
SELECT * FROM EMP;
和下列每一个都不同
SELECT * from EMP;   Select * From Emp;   SELECT * FROM EMP;
B. 两个语句所指的对象必须完全相同: 例如:
用户   对象名   如何访问
Jack   sal_limit  private synonym
   Work_city  public synonym
   Plant_detail  public synonym
Jill    sal_limit  private synonym
   Work_city  public synonym
   Plant_detail  table owner
考虑一下下列SQL语句能否在这两个用户之间共享.
SQL 能否共享  原因
select max(sal_cap) from sal_limit;
不能     每个用户都有一个private synonym - sal_limit , 它们是不同的对象
select count(*) from work_city where sdesc like 'NEW%';
能       两个用户访问相同的对象public synonym - work_city
select a.sdesc,b.location from work_city a , plant_detail b where a.city_id = b.city_id
不能 用户jack 通过private synonym访问plant_detail 而jill 是表的所有者,对象不同.
C. 两个SQL语句中必须使用相同的名字的绑定变量(bind variables) 例如:
第一组的两个SQL语句是相同的(可以共享),而第二组中的两个语句是不同的(即使在运行时,赋于不同的绑定变量相同的值)
a.
select pin , name from people where pin = :blk1.pin;
select pin , name from people where pin = :blk1.pin;
b.
select pin , name from people where pin = :blk1.ot_ind;
select pin , name from people where pin = :blk1.ov_ind;



5、调整数据库时用到的相关操作
重建当前用户下的所有索引
SELECT ' ALTER INDEX ' || T.INDEX_NAME || ' REBUILD;' FROM USER_INDEXES T;
SELECT ' ALTER INDEX ' || T.INDEX_NAME || ' REBUILD TABLESPACE 新表间名;' FROM USER_INDEXES T;
在线重建索引(online)
SELECT ' ALTER INDEX ' || T.INDEX_NAME || ' REBUILD ONLINE;' FROM USER_INDEXES T;
移动索引到新的表空间TBI_LONGHUI中
SELECT 'ALTER INDEX '|| T.INDEX_NAME ||' REBUILD TABLESPACE TBI_LONGHUI;' FROM USER_INDEXES T;
移动索引分区到新表空间
select t.index_name,t.partition_name,t.tablespace_name from user_ind_partitions t; 查看索引分区
ALTER INDEX 索引名 REBUILD  PARTITION  分区名 TABLESPACE 新表空间;


移动表到新的表空间TBS_LONGHUI
ALTER TABLE  表名 MOVE TABLESPACE TBS_LONGHUI;
移动表分区到新的表空间
select segment_name,segment_type,tablespace_name  from dba_segments  where wner='SRD'; 查看段所在的表空间
select t.table_name,t.partition_name,t.tablespace_name from user_tab_partitions t;查看分区表所在的表空间
ALTER TABLE  表名 MOVE PARTITION 表分区名 TABLESPACE 新表空间;


重新编译指定用户下的所有存储过程、函数和程序包,参数为用户模式名
execute dbms_utility.compile_schema('SCOTT');


监控指定用户下的所有索引
SELECT 'alter index ' || owner || '.' || index_name || ' monitoring usage;' FROM dba_indexes WHERE wner = 'SCOTT';
检查使用状态:select * from v$object_usage;
停止监控指定用户下的所有索引
SELECT 'alter index ' || owner || '.' || index_name || ' nomonitoring usage;' FROM dba_indexes WHERE wner = 'SCOTT';


ANALYZE_SCHEMA用于对某个用户拥有的所有TABLE,INDEX和CLUSTER的分析统计。
execute
dbms_utility.analyze_schema('LONGHUI','ESTIMATE',null,100);
100%的抽样百分比(9i)。或exec dbms_stats.gather_schema_stats(ownname =>
'LONGHUI', cascade =>true);(8i)


analyze index 索引名 validate
structure;分析一个索引后在同一个会话中查询index_stats才有数据select
(del_lf_rows_len/lf_rows_len)*100 浪费空间 from
index_stats;浪费空间大于20%的索引Oracle建议重建。


索引的分析
 使用ROWID获取行的成本依赖于索引聚集因子(clustering
factor),尽管聚集因子是索引的一个属性,它实际也关系到表数据块中被索引的字段值。一较低的聚集因子表明行被集中在表的少数块里,相反一个较高的
聚集因子表明行被随机分散到表的数据块中。因此,聚集因子过高意味着通过范围扫描用ROWID获取行成本会较高,因为需要访问表中过多的块才能返回数据。

图USER_INDEXES有一列clustering_factor,我们称为聚集因子,该列反映了数据相对于已索引的列是否有序。如果
clustering_factor列的值接近于索引中的树叶块(leaf
block)的数目,表中的数据就越有序,如果列的值接近于表中的行数(num_rows),则表中的数据则不是很有序。高
clustering_factor 的数值达到表中的行数 (num_rows),表明这些行的顺序与索引中的顺序不同,索引范围扫描将会需要额外的
I/O。
BLEVEL 二元高度每增加一个级别,都会增加DML操作的性能开销,重建索引来减小二元高度
Select i.index_name,i.blevel,i.clustering_factor,i.leaf_blocks,i.num_rows,i.last_analyzed 最近分析日期 from USER_INDEXES i;
 使用Oracle的Create Table As Select (CTAS) 语法来拷贝表格, 降低聚集因子
 使用create table tablename as select * from oldtable order by a,c 
Oracle在评估使用索引的代价(cost)时有两个重要的数据:CF(Clustering factor) 和 FF(Filtering factor)。
CF: 所谓 CF, 可以理解为每读入一个索引块要对应读入多少个数据块。
FF: 所谓 FF, 就是SQL语句所选择的结果集占总的数据量的百分比。

般的估算公式是:FF * (CF + 索引块个数) [备注:toms 说"the formula used by the CBO to
compute the cost is blevel + FF * leaf_blocks + FF *
clustering_factor"]由此估计出一个查询如果使用某个索引会需要读入的数据块块数。需要读入的数据块越多,则 cost
越大,Oracle 也就越有可能不选择使用 index。
(全表扫描需要读入的数据块数等于该表的实际数据块数)
其核心就是,CF可能会比实际的数据块数量大。CF受到索引中数据的排列方式影响,通常在索引刚建立时,索引中的记录与表中的记录有良好的对应关系,CF 都很小;在表经过大量的插入/修改操作后,这种对应关系越来越乱,CF也越来越大。这个时候就需要DBA重建该索引。
如果某个SQL语句以前一直使用某个索引,突然有一天,你发现系统慢的不行了,检查发现该SQL语句的某个索引用不上了:其中一个很大的可能就是 CF 已经变得太大,需要重新整理该索引了。
FF 则是Oracle 根据分析所做的估计。比如某表有50多万行,其主键的最小值是1,最大值是500000,考虑以下sql 语句:
Select * from table_name where keyid>=1; 和
Select * from table_name where keyid>=500000;
这两个表面看上去一样的sql语句,对Oracle而言却有巨大的差别。因为前者的FF是100%,而后者的FF可能只有 1%。如果它的CF大于实际的数据块数,则Oracle可能会选择完全不同的优化方式。



在可用的硬盘之间分布关键数据文件
    要特别注意的文件:system表空间、TEMPORARY表空间、回滚段或UNDO表空间、联机重做日志文件(最好放在最快的磁盘上)、放在ORACLE_HOME文件夹下的关键Oracle文件、经常被访问的表的数据文件、经常被访问的索引的数据文件
    经验总结:把上面提到的数据文件分布在各个可用的磁盘上
              把数据文件和索引文件分开放置
              对于经常连接的表,把他们的数据和索引表空间分开
              把控制文件的多个备份存储到不同的磁盘和控制器上
避免I/O磁盘争用,用下面的查询确定文件的I/O问题
系统表:
v$datafile:存储数据库中数据文件的信息
v$filestat:存储系统中访问数据文件的统计信息
SELECT
DF.NAME 文件名, FS.PHYRDS 读次数, FS.PHYWRTS 写次数, (FS.READTIM /
DECODE(FS.PHYRDS, 0, -1, FS.PHYRDS)) 读时间, (FS.WRITETIM
/DECODE(FS.PHYWRTS,0,-1,FS.PHYWRTS)) 写时间
FROM V$DATAFILE DF, V$FILESTAT FS WHERE DF.FILE# = FS.FILE# ORDER BY FS.READTIM DESC  或者
SELECT B.NAME, A.PHYRDS, A.PHYWRTS, A.READTIM, A.WRITETIM
FROM V$FILESTAT A, V$DBFILE B WHERE A.FILE# = B.FILE#
ORDER BY READTIM DESC
    说明:在磁盘上的物理写入和读取次数上如果出现很大的差别,就表明肯定有哪个磁盘负载过多!
    如果出现磁盘负载不平衡,可以通过移动数据文件来均衡文件I/O:
         alter tablespace tablespace_name offline;
         $cp /disk1/a.dbf /disk2/a.dbf;
         alter tablespace tablespace_name rename datafile '/disk1/a.dbf' to '/disk2/a.dbf';
         alter tablespace tablespace online;
         $rm /disk1/a.dbf


查看表和记录大小
SELECT A.OWNER, A.TABLE_NAME, A.NUM_ROWS, A.BLOCKS,
A.BLOCKS * C.VALUE / 1024 / 1024 "Size M", A.BLOCKS * C.VALUE /NUM_ROWS
"LEN(Byte)", A.EMPTY_BLOCKS, A.LAST_ANALYZED
FROM DBA_TABLES A,
(SELECT B.NAME, B.VALUE FROM V$PARAMETER B WHERE B.NAME =
'db_block_size') C WHERE A.TABLE_NAME = 'TB_PAY_AMOUNT'


查看表空间的名称及大小
SELECT T.TABLESPACE_NAME, ROUND(SUM(BYTES / (1024 * 1024)), 0) "TS_SIZE M" 
FROM DBA_TABLESPACES T, DBA_DATA_FILES D
WHERE T.TABLESPACE_NAME = D.TABLESPACE_NAME
GROUP BY T.TABLESPACE_NAME ORDER BY "TS_SIZE M" DESC


查看表空间物理文件的名称及大小
SELECT TABLESPACE_NAME, FILE_ID, FILE_NAME, ROUND(BYTES / (1024 * 1024), 0) TOTAL_SPACE
FROM DBA_DATA_FILES ORDER BY TABLESPACE_NAME;


查看表空间的使用情况
SELECT A.TABLESPACE_NAME, A.BYTES TOTAL, B.BYTES USED,
C.BYTES FREE, (B.BYTES * 100) / A.BYTES "% USED", (C.BYTES * 100)
/ A.BYTES "% FREE"
FROM SYS.SM$TS_AVAIL A, SYS.SM$TS_USED B, SYS.SM$TS_FREE C
WHERE A.TABLESPACE_NAME = B.TABLESPACE_NAME AND A.TABLESPACE_NAME = C.TABLESPACE_NAME;

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16486600/viewspace-521175/,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2008-12-25

  • 博文量
    41
  • 访问量
    187599