oracle 管理之道读书笔记2

1 闩锁
闩锁(Latch)的作用主要是保护数据的一致性。当很多会话用户请求同一个数据块时,要先获取闩锁才可以做动作。也就是说,当一个会话

用户要到数据库内找数据时,会先到数据库高速缓冲区中找,如果找不到表,就必须到数据文件中找。读出数据时,必须在数据库高速缓冲

区中获取足够的空闲空间,而要获取足够的空闲空间,会先去清理LRU List(把不常用的东西清出来);但要清理LRU List,必须先执行闩锁

操作,而对DB_BLOCK_ LRU_LATCHES参数的设置,表示决定使用几个闩锁。但基本上,闩锁的个数大于CPU的个数是没效益的
  闩锁的个数是可以由DB_BLOCK_LRU_ATCHES参数设置的。

闩锁的最大值可以由以下两点决定:

CPU的个数×2。

DB Block Buffer/50。

以这两项中的最小的值来算。


2
  DB_WRITER_PROCESSES
当数据库高速缓冲区需要读取或写回数据到数据文件中时,都需要通过DBWRn这个后台进程来协助处理,而DB_WRITER_PROCESSES主要就是设

置要由几个DBWRn来协助处理,最多可以达到10个。在此建议不要超过系统CPU的个数,如果设置的值超过了CPU的个数,那么超过的那些是

无法起作用的,

3 V$DB_CACHE_ADVICE
  。当开启参数DB_CACHE_ADVICE后,经过一段时间,Oracle就会自动收集足够的相关统计数据,并预测出DB_CACHE_SIZE在不同大小情况下

的性能数据,而这些数据就是通过V$DB_CACHE_ADVICE视图来显示的,因此,可以根据这些数据对DB_CACHE_SIZE做相关的调整,以达到最佳

情况。
  
  SELECT  ADVICE_STATUS,  
            SIZE_FOR_ESTIMATE,  
            ESTD_PHYSICAL_READ_FACTOR,  
            ESTD_PHYSICAL_READS  
  FROM  V$DB_CACHE_ADVICE  
WHERE  NAME = 'DEFAULT';  
   当ESTD_PHYSICAL_READ_FACTOR为1时,可以得出最好的cache分配内存。

4 V$BUFFER_POOL_STATISTICS
   可以查询V$BUFFER_POOL_STATISTICS来查看每个数据库高速缓冲区的命中率,方式如下:

SQL> SELECT name,1 - (physical_reads / (db_block_gets + consistent_gets))  
     "HIT_RATIO" FROM sys.v$buffer_pool_statistics  
WHERE db_block_gets + consistent_gets > 0;  
    对于SYS.V$BUFFER_POOL_STATISTICS,要先执行程序catclust.sql。

注意,原则上,获取命中率要在90%以上。

但回收率若是在90%以上,就代表这期间常用的数据是被放在回收池里的,而回收池里的数据又是经常被重复使用,所以,如果回收率是在

90%以上,就代表有问题,因为这代表90%以上的数据用完就丢了,应该将常用的数据放在保留池里。


5 共享池
  共享池(Share Pool)主要是存放最近执行过的SQL语句、数据字典与PL/SQL的一些数据、表的定义和权限等,包含库缓存、数据字典高速

缓存、控制结构、可重用运行时内存等部分

  1)库缓存
   共享SQL区域:当执行一个SQL语句时,Oracle就会为每一句SQL打开一个游标(Cursor),并提供一个共享SQL区域和私有SQL区域空间用于

存放,当发现两个以上的会话在使用同一个SQL语句时,Oracle就会重新组织共享SQL区域,使这些会话用户能重复使用此区域的内容,从而

不浪费宝贵的资源,同时,还会在私有SQL区域里保存一份这个SQL语句的副本;反之,如果没有找到相同的SQL语句,就必须重新进行完整

的分析作业,并将分析树(Parse Tree)以及执行计划等存放在共享池内,以备下次使用。这时要注意的是,在Oracle于共享池中寻找相同的

SQL语句的过程中,如果使用的SQL语句有任何一个地方不相同,Oracle就会将此SQL语句视为在此共享池中找不到,所以需要重新进行分析

。因此,如果同一段SQL语句只是在条件的部分输入不同的值,Oracle也会认为SQL语句不同,为此,可使用绑定变量(Bind Variable),意

思是Oracle会将变动的值视为绑定变量,这样很容易在共享池里找到相同的SQL语句
   当一条新的SQL语句被分析(Parse)时,Oracle从共享池中分配一块内存来存储共享SQL区域,而这块被分配的内存的大小与这条语句的复

杂性相关,如果共享池中的空间不够分配给共享SQL区域使用,Oracle就会启动LRU机制,将最近最少使用的内存块释放出来,直到有足够的

空间分配给新SQL语句的共享SQL区域;被释放出来的那块内存块内的SQL语句,如果再次被使用就必须重新分析,并重新分配共享SQL区域,

而这些动作都是比较消耗CPU的作业。这就是为何要使用绑定变量的原因了。因为如果没有使用绑定变量,当SQL语句中的变量的数值不同时

,Oracle就会将其视为一条新的语句,重复上面的分析、内存分配等动作,这都将大大消耗系统资源,降低Oracle系统性能。

 
   2) 数据字典高速缓存
    数据字典高速缓存是有关于数据库的参考信息、数据库的组织结构和数据库中的用户信息与权限等,而这些内容都是存储在表内,通常

以表和视图的形式进行呈现,就像经常使用到的V$xxx、DBA_xxx等系统的视图和表都是存储在数据字典(Data Dictionary)内。这里值得注

意的是,当SQL语句在分析的过程中时,也会去参考数据字典内的信息,而参考数据字典的动作所产生的SQL语句称为递归的SQL(Recursive

SQL),如果使用Statspack分析统计数据,此类的递归的SQL会被统计为Recursive Calls。

  3)重要概念
    基本上,共享池是依照修正过的LRU算法来判断其中的SQL语句与对象是否需要保留在共享池内。一般来说,当共享池需要为一个新的

SQL语句或对象分配内存时,会先确认是否有足够的空间,如果没有,就会将那些不经常使用的SQL语句和对象释放掉,也就是利用LRU机制

;但对于经常使用的SQL语句或对象,就会一直保留在共享池内。

除了LRU机制以外,当发生以下的情况时,Oracle也会将SQL语句从内存中释放出来:

当长时间没有被使用打开的游标(Open Cursor)时,SQL语句还是可能会从共享池中被释放出来,而此时如果还需要运行相关的SQL语句,

Oracle就会重新分析,并记录到共享SQL区域内。

当使用Analyze语句重新统计对象的信息时,所有与被分析对象相关的SQL语句都从共享池内被释放掉,这是因为重新分析对象,意味着原来

的执行计划可能不适用,所以必须将相关SQL语句都从共享池内释放掉,当再次使用到时,会重新分析并产生新的执行计划。

当对象的结构被修改过后,与该对象相关的所有共享SQL区域内都被注记为Invalid,当再次使用到相关的SQL语句时,就会再重新分析一次

。 
   Global Database Name被修改了,共享池内的所有信息都会被清空。

手动清空共享池的语句如下:

ALTER SYSTEM FLUSH SHARED_POOL;
当Oracle分析一个PL/SQL对象时,如过程、函数、触发器、包等,都需要从共享池中分配内存给这些对象。由于这些对象一般所占用的内存

空间都比较大,如包,因此分配的内存空间也相对较大,当Oracle经过长时间的运行后,共享池可能存在海量存储器碎片(Fragmentation)

,因而导致无法满足此类对象对于内存的需求。为了解决这类问题,Oracle专门从共享池内设置出一块共享的保留专用内存区域(Shared

Reserved Pool,简称保留区)来分配给这些具有内存需求的对象。这个保留区的默认值是共享池大小的5%,其大小一般建议是共享池的10%

,但绝对不要超过共享池大小的50%。除此之外,保留区的大小也可以通过参数SHARED_POOL_RESERVED_SIZE来调整,保留区的特点如下:

保留区是从共享池中分配,而不是直接从SGA中分配的,因此,保留区是共享池的一部分,用于存储大的对象。

在共享池中内存大于5 KB的对象就会被存放在共享池内的保留区,5 KB是默认值,而这个大小限制是可以通过隐藏参数

_SHARED_POOL_RESERVED_MIN_ ALLOC来设置的。除了在实例打开的过程中,所有小于这个数的对象永远都不会放到保留区,而大于这个值的

对象也永远不会存放到非保留区中。

当保留区有多余的内存空间时,对象也不会被放到共享池内的空间列表中,它有自己独立的保留空闭列表;相对的,当共享池空间不足时,

Oracle就利用LRU机制将不常用的对象释放,而不会影响到保留区内的对象。也就是说,保留区也是使用的LRU机制,但是在扫描时,其与共

享池是相互不影响的。

保留区内的信息可查询V$SHARED_POOL_RESERVED。关于V$SHARED_ POOL_RESERVED的详细内容,请参阅第2.3.5节。

前面提过Oracle在共享池中寻找相同的SQL语句的过程中,如果使用的SQL语句有任何一个地方不相同,Oracle就会视此SQL语句在此共享池

中找不到,所以需要重新进行分析,因此,若当同一段SQL语句只是在条件的部分输入了不同的值,Oracle也会将其视为不同的SQL语句,为

了适应这种情况,可使用绑定变量,但要如何判断SQL语句是否使用了绑定变量呢?可使用以下语句得知目前Hard Parse(硬分析)的次数与

比例,Hard Parse次数越少越好,所以比例值越接近于0越好。

select a.value as Total,b.value as "Hard Pase",  
        round(b.value / a.value, 2) as Ratio 
  from v$sysstat a, v$sysstat b  
where a.name = 'parse count (total)' and b.name = 'parse count (hard)';

  下面的语句查询哪些语句没使用变量绑定:
   oracle 9/10:
select d.plan_hash_value plan_hash_value,  
        d.execntexecnt,  
        a.hash_valuehash_value,  
        a.sql_textsql_text  
  from v$sqltext a,  
       (select plan_hash_value, hash_value, execnt  
           from (select c.plan_hash_value,  
                           b.hash_value,  
                           c.execnt,  
                               rank() over(partition by c.plan_hash_value order by  
b.hash_value) as hashrank  
                      from v$sql b,  
                            (select count(*) as execnt, plan_hash_value  
                                from v$sql  
                               where plan_hash_value <> 0  
                               group by plan_hash_value  
                              having count(*) > 10  
                                order by count(*) desc) c  
                    where b.plan_hash_value = c.plan_hash_value  
                    group by c.plan_hash_value, b.hash_value, c.execnt)  
          where hashrank <= 3) d  
where a.hash_value = d.hash_value  
order by d.execnt de SHARED_POOL_SIZEsc, a.hash_value, a.piece;  


oracle 11g:
   select d.plan_hash_value plan_hash_value,  
        d.execnt,
        a.HASH_VALUE,
        a.SQL_TEXT
  from v$sqltext a,  
       (select plan_hash_value, hash_value, execnt  
           from (select c.plan_hash_value,  
                           b.hash_value,  
                           c.execnt,  
                               rank() over(partition by c.plan_hash_value order by  
b.hash_value) as hashrank  
                      from v$sql b,  
                            (select count(*) as execnt, plan_hash_value  
                                from v$sql  
                               where plan_hash_value <> 0  
                               group by plan_hash_value  
                              having count(*) > 10  
                                order by count(*) desc) c  
                    where b.plan_hash_value = c.plan_hash_value  
                    group by c.plan_hash_value, b.hash_value, c.execnt)  
          where hashrank <= 3) d  
where a.hash_value = d.hash_value  
order by d.execnt desc, a.hash_value, a.piece;  


6 共享池的重要参数
  1)  SHARED_POOL_SIZE
      SHARED_POOL_SIZE指定了共享池的大小。在32位操作系统中,此参数的默认值是8 MB,而64位操作系统中的默认值是64 MB。

提示

Oracle 9i之前的版本和10g版本的共享池的算法是不相同的,差异如下:

Oracle 9i的算法是SHARED_POOL_SIZE的设置加上内部SGA消耗大小,因此,如果以SHOW PARAMETER SHARED_POOL_SIZE查询V$SGASTAT,并汇

总共享池的大小是不相同的。

Oracle 10g的算法是当设置了SHARED_POOL_SIZE的值,就将内部SGA消耗大小算在其中,因此,共享池真正使用的空间是SHARED_POOL_SIZE

的设置值减去内部SGA消耗大小。在10g中设置共享池的大小时必须加入这个因素,如果共享池的设置太小,在打开数据库时,将会有ORA-

0371的错误信息。

2)一般情况下,会发现保留区是很少被使用的,也就是说,5%~10%的保留区空间可能有些浪费。不过,建议经过长时间的观察再决定是否

需要调整保留区的大小。

V$SHARED_POOL_RESERVED的使用方式如下:

(1) 确认SHARED_POOL_RESERVED_SIZE的空间情况,查询语句如下:

SELECT ROUND(FREE_SPACE / 1024 / 1024, 1) "FREE SPACE MB",  
            REQUEST_MISSES,  
            REQUEST_FAILURES  
  FROM V$SHARED_POOL_RESERVED;  
  
  上结果的详细说明如下所示:

当REQUEST_FAILURES大于0时,增加SHARED_POOL_SIZE和SHARED_ POOL_RESERVED_SIZE的空间。

当REQUEST_MISS等于0,或是FREE_MEMORY大于等于SHARED_POOL_ RESERVED_SIZE的空间时,则增加SHARED_POOL_RESERVED_SIZE的空间。

(2) 确认SHARED_POOL_RESERVED_SIZE的命中率(Hit Ratio),查询语句如下:

SELECT (REQUEST_MISSES / (REQUESTS + 0.0001)) * 100 "REQUEST MISSES RATIO",  
        (REQUEST_FAILURES / (REQUESTS + 0.0001)) * 100 "REQUEST FAILURES RATIO"  
  FROM V$SHARED_POOL_RESERVED;  

   以上结果应该都要小于1%,如果大于1,应该加大SHARED_POOL_RESERVED_ SIZE



(3) V$SQL、V$SQLTEXT、V$SQLAREA与V$SQL_PLAN
    V$SQL、V$SQLTEXT、V$SQLAREA与V$SQL_PLAN这4个视图都是查询在共享池中的SQL语句,而妥善的交互利用这些视图对于实例Tuning和

SQL Tuning有相当大的帮助。

V$SQL是共享池中已经分析过的SQL,其中列出了所有SQL的相关信息,但不包含GROUP BY语句,每一个SQL语句都是一笔数据,但此记录只保

留SQL语句的前1000个字符。

V$SQLAREA中记录了在共享池中分析过的每个SQL语句和准备运行的SQL语句的统计数据,和V$SQL一样只保留SQL的前1000个字符。

V$SQLTEXT视图会记录完整的SQL,但会将SQL分成不同笔的数据来存储。

V$SQL_PLAN视图包含了库缓存中所有游标所产生的执行计划,可结合V$SQLAREA获得库缓存中所有语句的查询计划。

V$SQL、V$SQLTEXT、V$SQLAREA与V$SQL_PLAN的运用如下所示:

利用V$SQL查询出使用频率最高的10句SQL:

select sql_text, executions  
  from (select sql_text,  
                    executions,  
                    rank() over(order by executions desc) exec_rank  
           from v$sql)  
where exec_rank <= 10;  
利用V$SQL查询出最耗费磁盘读的前10句SQL:
select disk_reads, sql_text  
  from (select sql_text,  
                                disk_reads,  
                                dense_rank() over(order by disk_reads desc) disk_reads_rank  
            from v$sql)  
where disk_reads_rank <= 10;  
利用V$SQL查询出最耗费内存的前10句逻辑读SQL语句:
select buffer_gets, sql_text  
  from (select sql_text,  
         buffer_gets,  
         dense_rank() over(order by buffer_gets desc) buffer_gets_rank  
           from v$sql)  
where buffer_gets_rank <= 10;  
利用V$SQLAREA和V$SQLTEXT查看消耗资源最多的SQL语句,步骤如下。
A SELECT hash_value, executions, buffer_gets, disk_reads, parse_calls  
FROM V$SQLAREA  
WHERE buffer_gets > 10000000 OR disk_reads > 1000000  
ORDER BY buffer_gets + 100 * disk_reads DESC;  
b  得到HASH_VALUE后,再利用V$SQLTEXT查询出实际的SQL语句。

select ADDRESS, HASH_VALUE, PIECE, SQL_TEXT  
  from v$sqltext  
where hash_value = '2450129223'  
order by PIECE;  

  利用V$SQLAREA查询出磁盘读次数超过100 000的查询语句,也就是最耗资源的SQL语句,语句如下:
select b.username "USER NAME",  
a.disk_reads "DISK READ",  
a.executions EXECUTIONS,  
a.disk_reads / decode(a.executions, 0, 1, a.executions) "READ_EXEC%",  
a.sql_text "SQL TEXT"  
  from v$sqlarea a, dba_users b  
where a.parsing_user_id = b.user_id  
   and a.disk_reads > 100000  
order by a.disk_reads desc;  

  利用V$SQL和V$SQL_PLAN查询出SQL语句的执行计划,步骤如下:
A  利用V$SQL查出查询的SQL语句的ADDRESS和HASH_VALUE,语句如下:

SELECT sql_text, address, hash_value FROM v$sql  
WHERE sql_text like 'SELECT * FROM EMP %'; 
B  利用查出的ADDRESS和HASH_VALUE,配合V$SQL_PLAN相对应的字段,即可查询出此SQL语句的执行计划,语句如下;
SELECT operation, options, object_name, cost FROM v$sql_plan  
WHERE address = '32557612' AND hash_value =2128902247;  

  利用V$SESSION的SQL_HASH_VALUE和SQL_ADDRESS字段,配合V$SQLTEXT的HASH_VALUE和ADDRESS,可查询出当前用户链接的SQL语句,步骤

如下
  a  利用V$SESSION查询出SQL_HASH_VALUE和SQL_ADDRESS,语句如下
   SELECT USERNAME,  
            TERMINAL, PROGRAM,  
            SQL_HASH_VALUE,  
            SQL_ADDRESS, TYPE  
  FROM V$SESSION  
WHERE TYPE NOT LIKE 'BACKGROUND'; 

b  利用查出的SQL_HASH_VALUE和SQL_ADDRESS,再配合V$SQLTEXT相对应的字段即可,语句如下;
    SELECT *  
  FROM V$SQLTEXT  
WHERE HASH_VALUE = '889124229'  
   AND ADDRESS = '000000008EBE3A38'  
ORDER BY PIECE; 

(3)  V$LIBRARYCACHE
  V$LIBRARYCACHE的内容包含了关于库缓存的性能统计信息,对于共享池的性能优化有很大帮助
    此表中必须特别注意PIN和GET的命中率或未命中率,当命中率小于99%或未命中率大于1%时,说明Hard Parse过多,可能需要加大共享池或是使用绑定变量等优化的动作。查询命中率的语句如下:

Select  
            namespace,  
            gets,  
            gethitratio*100 "GET%",  
            pins,  
            pinhitratio*100 "PIN%",  
            reloads,  
            invalidations 
from 
            v$librarycache;
  



猜你喜欢

转载自jackyrong.iteye.com/blog/1689329
今日推荐