Profilezhanjie的共享空间PhotosBlogLists Tools Help

Blog


    July 24

    v$sql v$sqlarea v$sqltext

    V$SQL       Child cursor details for V$SQLAREA

    V$SQLAREA   Shared pool details for statements/anonymous blocks

    V$SQLTEXT   SQL text of statements in the shared pool

                都是通过ADDRESSHASH_VALUE可以为一判定一个SQL

                在两个不同的用户里分别建立wwm表,用两个用户分别运行select * from wwm.则在v$sql里是两条记录(两个cursor), ADDRESSHASH_VALUE却是相同的。但在v$sqlarea,v$sqltext却只有一条记录。V$sqlarea v$sql合并cursor后的结果.可以通过v$sqlPLAN_HASH_VALUE来判断两个SQL的执行计划是否相同。

                V$sqltext能查到SQL语句的全部(将一个SQL分为多条记录,每条记录64字节,通过HASH VALUE来判断是否属于一条SQL),但v$sql, v$sqlarea只显示1000字节。所以要访问V$SQLTEXT最好根据piece去排序,来组织正确的SQL

                A用户执行SELECT * FROM WWM ORDER BY ID 1次,用B用户执行SELECT * FROM WWM ORDER BY ID 3次,则

    select sql_text,sorts from v$sql

    where sql_text like '%wwm%'

    SQL_TEXT                                         SORTS

    --------------------------------------------------------------------------------

     

    select * from wwm order by id           3

    select * from wwm order by id           1

     

    select sql_text,sorts from v$sqlarea

    where sql_text like '%wwm%'

    SQL_TEXT                                              SORTS

    --------------------------------------------------------------------------------

    select * from wwm order by id           4

     

    查找耗费资源的SQL

      1  SELECT hash_value, executions, buffer_gets, disk_reads, parse_calls

      2    FROM V$SQLAREA

      3   WHERE buffer_gets > 10000000

      4      OR disk_reads > 1000000

      5*  ORDER BY buffer_gets + 100*disk_reads DESC

    SQL> /

     

    HASH_VALUE EXECUTIONS BUFFER_GETS DISK_READS PARSE_CALLS

    ---------- ---------- ----------- ---------- -----------

    2653134598          2       73426      33572           2

    1813062183       7424     1127737        293        6497

    2964631876       9377      818505          5        9365

    1169272907      31598      521484          0       12817

     664977058       1202      301733         11           2

    3195782399       4209      266893         13        4209

     895481279      15786      236850        227       12853

       3722848       7285      124008          0        5050

     264196705       7285      109275        118        4925

    数据类型内部结构存储

    SQL> create table wwm( thechar char(10),thevarchar varchar2(20),thenumber number(10,2));

    Table created.

    SQL> select * from wwm;

     

    THECHAR    THEVARCHAR            THENUMBER

    ---------- -------------------- ----------

    dsffg      varchar2                   10.2

    wwm        wwmwwm2                   -999.2

    charcharch charcharcharcharchar  100000000

      1* select thechar,dump(thechar) from wwm

    SQL> /

    THECHAR                                                                                             DUMP(THECHAR)

    -----------------------------------------------------------

    Dsffg                                                                            Typ=96 Len=10: 100,115,102,102,103,32,32,32,32,32

    Wwm                                                                           Typ=96 Len=10: 119,119,109,32,32,32,32,32,32,32

    Charcharch                                                                    Typ=96 Len=10: 99,104,97,114,99,104,97,114,99,104

    可以看到THECHARCHAR Typ=96)类型的(NCHAR也是96),长度是10Len=10),不足长度的补空(32

    SQL> select thevarchar,dump(thevarchar) from wwm;

    THEVARCHAR                                                                          DUMP(THEVARCHAR)

    --------------------------------------------------------------------------------------

    varchar2                                                                                    Typ=1 Len=8: 118,97,114,99,104,97,114,50

    wwmwwm2                                                                  Typ=1 Len=7: 119,119,109,119,119,109,50

    charcharcharcharchar                                         Typ=1 Len=20: 99,104,97,114,99,104,97,114,99,104,97,114,99,104,97,114,99,104,97,114

    可以看到THEVARCHARVARCHAR2 Typ=1)类型的,NVARCHAR2也是1

     

    SQL> select thenumber,dump(thenumber) from wwm;

     THENUMBER                                                                           DUMP(THENUMBER)

    -----------------------------------------------------

          10.2                                                                                                Typ=2 Len=3: 193,11,21

        -999.2                                                                                               Typ=2 Len=5: 61,92,2,81,102

     100000000                                                                                           Typ=2 Len=6: 196,100,100,100,100,100

    可以看到thenumberNUMBER Typ=2)类型的(FLOAT也是2),

     

    select dump(address,16) from v$sqlarea where rownum = 1;

    DUMP(ADDRESS,16)

    --------------------------------------------------------------------------------

    Typ=23 Len=8: 7,0,0,0,47,c9,a4,98

    RAW     Typ=23

     

      1* select thedate,dump(thedate) from wwm6

    THEDATE                                                                     DUMP(THEDATE)

    --------------------------------------------------------------------------------

    05-JUN-06                                                                    Typ=12 Len=7: 120,106,6,5,17,16,11

    DATE类型Typ=12

    CENTURY120-100=20

    Year:       106-100=06

    Month=6

    Day=5

    Hours=17-1=16

    Minutes=16-1=16

    Seconds=11-1=10

     

    SQL> select sysdate,dump(sysdate) from dual;

    SYSDATE                                                                     DUMP(SYSDATE)

    ---------------------------------------------------------

    07-6 -06                                                                    Typ=13 Len=8: 214,7,6,7,14,57,43,0

    SYSDATETyp=13

     

    排序,加减等操作就是根据DUMP的结果来排序的(会经过与或等运算,但基数不同,不在这里讨论),

     

    这里只是列出了常用的类型,希望大家以后在读内部结构的时候发现Typ=XX时会想起这篇文章。谢谢

    ORA-03237: Initial Extent of specified size cannot be allocated in tablespace

    问题是在建立LOB字段时发生的,用 dmsdeuser1用户执行

    SQL> connect dmsdeuser1/pass@sid

    SQL> CREATE TABLE CONTENT  (

      2     MSG_ID               CHAR(100)                       NOT NULL,

      3     MSG_DATA             BLOB,

      4     CONSTRAINT PK_CONTENT PRIMARY KEY (MSG_ID)

      5  );

    CREATE TABLE CONTENT  (

    ERROR at line 1:

    ORA-03237: Initial Extent of specified size cannot be allocated in tablespace

    (DATA01)

     dmsdeuser1用户默认表空间是DATA01,是UNLIMITED

    首先看表空间是否有空余空间

    SQL> 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;

     

    TABLESPACE_NAME                                                   TOTAL

    ------------------------------------------------------------ ----------

          USED       FREE     % USED     % FREE

    ---------- ---------- ---------- ----------

     DATA01                                                       2147483648

       1081344 2146336768 .050354004 99.9465942

     

    SYSTEM                                                        419430400

     416677888    2686976   99.34375    .640625

     

    UNDOTBS1                                                      209715200

       4898816  204668928  2.3359375   97.59375

     

     虽然DATA01空间是够的,但还是做了一下扩展,SYSTEM表空间将要用尽,也扩展下。

     alter database datafile 'D:\ORACLE\ORADATA\DE2\SYSTEM01.DBF' resize 600M;

    alter database datafile 'D:\ORACLE\ORADATA\DE2\DATA01' resize 3000M;
    错误依旧
    select * from dba_tablespace;

    TABLESPACE_NAME                                              BLOCK_SIZE

    ------------------------------------------------------------ ----------

    INITIAL_EXTENT NEXT_EXTENT MIN_EXTENTS MAX_EXTENTS PCT_INCREASE MIN_EXTLEN

    -------------- ----------- ----------- ----------- ------------ ----------

    STATUS             CONTENTS           LOGGING            FORCE_

    ------------------ ------------------ ------------------ ------

    EXTENT_MANAGEMENT    ALLOCATION_TYPE    PLUGGE SEGMENT_SPAC

    -------------------- ------------------ ------ ------------

    SYSTEM                                                             8192

             65536                       1  2147483645                   65536

    ONLINE             PERMANENT          LOGGING            NO

    LOCAL                SYSTEM             NO     MANUAL

     

    DATA01                                                             8192

             16384       16384           1  2147483645            0      16384

    ONLINE             PERMANENT          LOGGING            NO

    LOCAL                UNIFORM            NO     MANUAL

     

    DATA02                                                             8192

           1048576     1048576           1  2147483645            0    1048576

    ONLINE             PERMANENT          LOGGING            NO

    LOCAL                UNIFORM            NO     AUTO

     

    SQL> show parameter block

     

    NAME                                 TYPE

    ------------------------------------ ----------------------

    VALUE

    ------------------------------

    db_block_size                        integer

    8192

     问题就在这里了,平常,数据库分配的最小EXTENT是两个BLOCK_SIZE,也就是16K,而DATA01表空间的INITIAL EXTENT正好是16K,不会出什么问题。但是LOB等需要至少3个BLOGKS,而RBS需要4个。所以在DATA01表空间是无法建立LOG字段的。

      1  create  tablespace data02  datafile 'D:\ORACLE\ORADATA\DE2\DATA02' size 2000M

      2* extent management local uniform size 1M segment space management auto

    SQL> /

     Tablespace created.

     SQL> alter user dmsdeuser1 default tablespace data02;

     User altered.

     SQL> alter user dmsdeuser1 quota unlimited on data02;

     User altered.

     

    SQL> connect dmsdeuser1/pass1@sid

    Connected.

    SQL> CREATE TABLE CONTENT  (

      2     MSG_ID               CHAR(100)                       NOT NULL,

      3     MSG_DATA             BLOB,

      4     CONSTRAINT PK_CONTENT PRIMARY KEY (MSG_ID)

      5  )

      6  /

     Table created.

    ORACLE CPU过高的一次调整过程

    发现CPU占用率一般都维持在90%以上,由于大量使用FOR UPDATE,造成大量LATCH等等待现象,其中某些多线程SQL又运行非常频繁。很久以前就发现这些问题,给出相对意见,建议不采用FOR UPDATE或在FOR UPDATE上加NOWAIT(见http://spaces.msn.com/sunmoonking/blog/cns!E3BD9CBED01777CA!318.entry   “ELECT FOR UPDATE 相关的知识”一章  ),由于项目进程问题一直没进行程序修改,决定在这次解决掉,以解后顾之忧。
     
    调整前要知道如下问题
          1,CPU是多少MHZ
          2,SERVER 端的CPU是否有负荷较重
          3,CLIENT 端的CPU是否有负荷较重
          4,空闲时间(如半夜)CPU使用率是否超过15%,如果超过则需要特别注意了
          5,CPU的PEAK LOAD
          6,CPU的IDLE STATE
     
    影响CPU的因素
    1,高的无必要的解析会代价昂贵。
         发现那些SQL运行了大量的PARSE
         select sql_text, parse_calls, executions from v$sqlarea order by parse_calls desc;
         SYS的总的PARSE情况
         select name, value from v$sysstat where name = ’parse count%’;
         只有硬解析才能减少,可以绑定变量,或增加每一个SESSION的CACHED CURSORS。
    2,导致大量I/O的SQL也会明显占用CPU,如没有INDEX。BUFFER GETS一般会同CPU一块增长。可以通过v$sqlarea发现buffer_gets
    3,其他等待时间,可以通过v$sesstat,v$sysstat查看
     
    #VMSTAT 5 5 的CPU部分
          us  user用掉的
          sy  system用掉的
          id  空闲
     
    调整前
    TOPAS
          Name            PID  CPU%  PgSp Owner
          oracle       688416  25.2   4.6 orasbp
          oracle       569658  24.9   4.5 orasbp
          topas        676210   0.1   2.9 root
          syncd         77964   0.0   0.5 root
          hatsd        159792   0.0   8.3 root
    或者ps aux|head
    检查CPU数量
          /usr/sbin/bindprocessor -q
          The available processors are:  0 1 2 3
     
    STATSPACK的信息
                                                         Total Wait   wait    Waits
    Event                               Waits   Timeouts   Time (s)   (ms)     /txn
    ---------------------------- ------------ ---------- ---------- ------ --------
    enqueue                             5,465        121      1,793    328      0.6
    latch free                          2,986      2,669         21      7      0.3
    根据消耗最多CPU的进程PID来得到SID详细信息
    select s.sid from v$process p, v$session s
    where s.paddr=p.addr and p.spid =  &your_spid;
    根据SID查SQL
    SELECT SQL_TEXT from V$SQLTEXT_WITH_NEWLINES where HASH_VALUE
    = (select sql_hash_value from v$session
    where SID = <problem_SID_you_got_from_last_step>) ;
    还有
    select n.name,s.value
    from v$statname n,V$sesstat s
    where n.statistic# = s.statistic#
    and value > 0
    and s.sid = (select a.sid from v$process p,v$session a
    where p.addr =a.paddr
    and a.terminal = userenv(’terminal’))
    order by n.class,n.name
    用以上SQL完成SHELL(shell信息在后面whoit.sh),运行
    sh whoit.sh 688416  来根据PID得到用户信息和SQL语句
     
    在STATSPACK和我的whoit.sh都指定是这个SQL的问题
    SELECT demessageid, fromid, apptype, demessage,appversion,vovers
    ion ,toid,tag FROM de_receivelog  WHERE (status = :1 and rownum<
    =1 and (dealtime is null or dealtime<sysdate) and delock=0) or (
    delock=1 and Update_Date<sysdate-2/24) order by RECEIVETIME for
    update
     
    再看等待事件
     select sid||' '||event||' '|| total_waits||' '||average_wait               from v$session_event where sid=25
    SQL> /
    SID||''||EVENT||''||TOTAL_WAITS||''||AVERAGE_WAIT
    --------------------------------------------------------------------------------
    25 latch free 46180 1
    25 control file sequential read 4 0
    25 log file sync 1 0
    25 db file sequential read 202 0
    25 db file scattered read 445 1
    25 SQL*Net message to client 22 0
    25 SQL*Net message from client 22 0
     
    只有一个DEFAULT 池
    NAME                                      HIT_RATIO
    ---------------------------------------- ----------
    DEFAULT                                   .88042806
     
    设置db_keep_cache_size池,并KEEP表
    ALTER  TABLE customer STORAGE (BUFFER_POOL  RECYCLE|KEEP|DFAULT)
    SQL> analyze table sbpopt.de_receivelog compute statistics;
    建立相关索引
    alter table  TI_REPAIR_DEED storage(buffer_pool keep);
    alter table  de_receivelog  storage(buffer_pool keep);

     
    看到相关的等待都是LATCH FREE,enqueue,估计是由于SELECT FOR UPDATE并且全表扫描造成的
    查看每个Session的CPU利用情况:
    select ss.sid||' '||se.command||' '||ss.value CPU ||' '||se.username||' '||se.program
    from v$sesstat ss, v$session se
    where ss.statistic# in
    (select statistic#
    from v$statname
    where name = 'CPU used by this session')
    and se.sid=ss.sid
    and ss.sid>6
    order by ss.value
     
    根据STATSPACK的HASH VALUE 用SQL>@sprepsql得到
    STATSPACK SQL report for Hash Value: 1710202187  Module: JDBC Thin Client
    DB Name         DB Id    Instance     Inst Num Release     Cluster Host
    ------------ ----------- ------------ -------- ----------- ------- ------------
    SBP           3008872479 SBP                 1 9.2.0.6.0   NO      svodbp01
     Start Id     Start Time         End Id      End Time       Duration(mins)
    --------- ------------------- --------- ------------------- --------------
           44 23-May-06 14:13:01         45 23-May-06 14:28:00           14.98
    SQL Statistics
    ~~~~~~~~~~~~~~
    -> CPU and Elapsed Time are in seconds (s) for Statement Total and in
       milliseconds (ms) for Per Execute
                                                           % Snap
                         Statement Total      Per Execute   Total
                         ---------------  ---------------  ------
            Buffer Gets:       6,938,821          7,608.4   63.34
             Disk Reads:               0              0.0     .00
         Rows processed:             197              0.2
         CPU Time(s/ms):             508            557.2
     Elapsed Time(s/ms):             607            665.8
                  Sorts:           1,292              1.4
            Parse Calls:             191               .2
          Invalidations:               0
          Version count:               1
        Sharable Mem(K):              22
             Executions:             912
    SQL Text
    ~~~~~~~~
    SELECT demessageid, fromid, apptype, demessage,appversion,vovers
    ion ,toid,tag FROM de_receivelog  WHERE (status = :1 and rownum<
    =1 and (dealtime is null or dealtime<sysdate) and delock=0) or (
    delock=1 and Update_Date<sysdate-2/24) order by RECEIVETIME for
    update nowait
    ===============================================================
    15分钟内执行了912次,占用22K内存(不多),每次执行1.4个排序,共花了508秒,由于已经采取措施将此表KEEP与内存中,因此没有磁盘读,但每次的逻辑读7,608.4个块
     
    然后将SQL语句的FOR UPDATE改成 FOR UPDATE NOWAIT;     这才是真正解决问题的地方
    至此,通过观察CPU一般维持在25%以内。
     
    等待事件
    enqueue(队列)  Indicates waits associated with internal queuing mechanism for locking various resources and components of Oracle. Please refer to Appendix B of the Oracle8i Reference Manual for the complete list of enqueues in Oracle.是一种保护共享资源的琐,锁可以保护纪录里面数据一类的共享资源,防止两个人同时修改该纪录,fifo,enqueue等待通常是 ST enqueue,HW enqueue ,TX4 enqueue。ST enqueue在数据字典管理方式表空间的物理空间分配和管理上发挥作用。当有此问题时可以转变为本地管理表空间或预先分配扩展。HW enqueue同段的高水位线一起使用,手工分配扩展可避免其上的等待。TX4 是最常见的,1,唯一索引的重复,需要COMMIT/ROLLBACK来释放ENQUEUE。2,多个并发的对同一位图索引片的修改,同上。3,多用户同时修改相同的数据块,如果已经没有空闲的ITL槽,则会引发一数据块的锁,运用增大initrans或maxtrans以容纳更多ITL槽的方法来解决,或增大PCTFREE。(ST:使用本地表空间或预先分配大扩展,HW预先分配扩展于高水水位线之上,TX4增大表或索引的initrans和maxtrans,TM为外键建立索引,察看日志放在快速磁盘上)
    latch free(锁存器空闲,拴空闲) Indicates latch contention for the latch# that is being waited on. Ensure that you already have tuned the number of latches to their allowed maximums by setting the relevant init.ora parameters. If the problem persists, you should determine what is causing the contention for the latch and fix the underlying problem. Your goal should be to cure the disease not the symptom. A latch free event is a symptom of a bigger problem. For example, if the latch# derived from this is a library cache latch (assuming that the shared pool is configured appropriately), it may indicate a significant amount of hard parsing. This usually is a problem with applications that have hard-coded values in them. Either rewrite them with bind variables or upgrade to Oracle8i and use CURSOR_SHARING=force (or just look the other way).Latch Free是一种低级的同步锁机制,用以维持某些访寻和执行操作的顺序。Oracle通过enqueue来达成对重做线程/表/事务一类对象的并发使用,而通过Latch来达成对SGA中共享内存结构的保护。Latch速度快而成本低,往往通过单个的内存单元来实现。大部分Latch是互斥的。共享型Latch许可对其内存结构的并发读操作。当请求得到Latch但它已被其它进程占住时,将产生一条Latch free miss的纪录。大多数Latch问题关联到不使用绑定变量(Library Cache Latch),重做日志生成中问题(Redo Allocation Latch),内存缓冲区竞争问题(Cache Buffers LRU Chain)和内存缓冲区中‘热块’的数据块(Cache Buffers Chain)。也有一些Latch Waits是由软件错误而造成的。    首先确认足够的LATCH数,然后确认那个锁存器(V$SESSION_WAIT的P2),再确认是什么引起的.
     
    #cat whoit.sh
    sqlplus /nolog <<EOF
       connect / as sysdba
       col machine format a30
       col program format a40
       set line 200
       select sid,serial# ,username,osuser,machine,program,process,to_char(logon_time,'yyyy/mm/dd hh24:mi:ss')
                from v\$session where paddr in
                ( select addr from v\$process where spid in($1));
       select sql_text from v\$sqltext_with_newlines  
                where hash_value in       
                (select SQL_HASH_VALUE from v\$session where       
                     paddr in (select addr from v\$process where spid=$1)   
              )         
                order by piece;         
     exit;
     EOF

    PROCEDURE行变列与输出

    CREATE OR REPLACE procedure get_activity_code(in_activity_code in tm_recall_activity.activity_code%type,out_curEmp out SYS_REFCURSOR)
    IS
         Col_c2 VARCHAR2(4000);
         Col_maxday number(5);
         the_day_count number(5);
         the_sql varchar2(4000);
    BEGIN
         the_day_count:='1';                     --计数器
         select max(floor(c.repair_date-e.startdate)) INTO  Col_maxday         --计算最大列数,因为列数是不固定的,比如此处是38
              from tt_activity_vehicle c,tm_recall_activity e
              where e.recall_activity_id=c.recall_activity_id and e.activity_code='L001';
         IF  Col_maxday IS NULL THEN
              dbms_output.put_line('NO MAXDAY');
         END IF;
         the_sql:='select b.rssc_name as rssc,d.labor_no as type ';
         while the_day_count<=Col_maxday LOOP            --循环拼语句
              the_sql:=the_sql||',decode(floor(c.repair_date-e.startdate),'||the_day_count||',count(*),0)';
              the_day_count:=the_day_count+1;                   --加一,要拼出满足需要的列来,比如循环38次
         END LOOP;
         the_sql:=the_sql||' from tm_sst a,tm_rssc b,tt_activity_vehicle c,ti_workitem_detail           d,tm_recall_activity e
              where c.operate_sst_code=a.sst_code and a.rssc_id=b.rssc_id
              and e.recall_activity_id=c.recall_activity_id
              and e.activity_code='''||in_activity_code||'''                      --参数
              and d.labor_no in           (''MFJC0000'',''WXBY0000'',''WXBY1000'',''JCWB0000'',''JWBL0000'',''LP000000'',''JCDQ0000'')
              and c.operate_sst_code=d.sst_code and c.bill_no=d.bill_no
              group by b.rssc_name,(c.repair_date-e.startdate),d.labor_no order by           b.rssc_name,d.labor_no,floor(c.repair_date-e.startdate)';
    --execute immediate the_sql;
         open out_curEmp for the_sql;                                            --PROCEDURE的输出关键
         EXCEPTION
         WHEN OTHERS THEN
              raise_application_error(-200020,'Error in get_activity_code'||SQLCODE);
         end get_activity_code;
    /
     
    ----------------------------------------------------------------------------------------------------------------------
    运行
    SQL> var rset refcursor;
    SQL> exec get_activity_code('L001',:rset);
    SQL> print rset;
    -----------------------------------------------------------------------------------------------------------------------
    原来的SQL是这个样子
      1  select b.rssc_name as rssc,d.labor_no as type ,count(*) as num ,floor(c.repair_date-e.startdate) as xday
      2  from tm_sst a,tm_rssc b,tt_activity_vehicle c,ti_workitem_detail d,tm_recall_activity e
      3  where c.operate_sst_code=a.sst_code and a.rssc_id=b.rssc_id
      4  and e.recall_activity_id=c.recall_activity_id
      5  and e.activity_code='L001'
      6  and d.labor_no in ('MFJC0000','WXBY0000','WXBY1000','JCWB0000','JWBL0000','LP000000','JCDQ0000') and c.operate_sst_code=d.sst_code and c.bill_no=d.bill_no
      7* group by b.rssc_name,(c.repair_date-e.startdate),d.labor_no order by b.rssc_name,xday
    SQL> /
    辽宁分销中心   MFJC0000                  1          2
    辽宁分销中心   JCDQ0000                  1         38
    辽宁分销中心   MFJC0000                  1         38
     
    前两列不说了,第三列是数量,第四列是距离开始的天数(用来定位第三列应该显示的列的位置,比如第四列是38,则第三列的1应该在第38列处(不算前两列))
     
    ---------------------------------------------------------------------------------------------------------------------------------
    最后拼出的SQL是这个样子
    select b.rssc_name as rssc,d.labor_no as type
    ,decode(floor(c.repair_date-e.startdate),1,count(*),0),decode(floor(c.repair_date-e.startdate),2,count(*),0),
    decode(floor(c.repair_date-e.startdate),3,count(*)),decode(floor(c.repair_date-e.startdate),4,count(*)),
    decode(floor(c.repair_date-e.startdate),5,count(*)),decode(floor(c.repair_date-e.startdate),6,count(*)),
    decode(floor(c.repair_date-e.startdate),7,count(*)),decode(floor(c.repair_date-e.startdate),8,count(*)),
    decode(floor(c.repair_date-e.startdate),9,count(*)),decode(floor(c.repair_date-e.startdate),10,count(*)),
    decode(floor(c.repair_date-e.startdate),11,count(*)),decode(floor(c.repair_date-e.startdate),12,count(*)),
    decode(floor(c.repair_date-e.startdate),13,count(*)),decode(floor(c.repair_date-e.startdate),14,count(*)),
    decode(floor(c.repair_date-e.startdate),15,count(*)),decode(floor(c.repair_date-e.startdate),16,count(*)),
    decode(floor(c.repair_date-e.startdate),17,count(*)),decode(floor(c.repair_date-e.startdate),18,count(*)),
    decode(floor(c.repair_date-e.startdate),19,count(*)),decode(floor(c.repair_date-e.startdate),20,count(*)),
    decode(floor(c.repair_date-e.startdate),21,count(*)),decode(floor(c.repair_date-e.startdate),22,count(*)),
    decode(floor(c.repair_date-e.startdate),23,count(*)),decode(floor(c.repair_date-e.startdate),24,count(*)),
    decode(floor(c.repair_date-e.startdate),25,count(*)),decode(floor(c.repair_date-e.startdate),26,count(*)),
    decode(floor(c.repair_date-e.startdate),27,count(*)),decode(floor(c.repair_date-e.startdate),28,count(*)),
    decode(floor(c.repair_date-e.startdate),29,count(*)),decode(floor(c.repair_date-e.startdate),30,count(*)),
    decode(floor(c.repair_date-e.startdate),31,count(*)),decode(floor(c.repair_date-e.startdate),32,count(*)),
    decode(floor(c.repair_date-e.startdate),33,count(*)),decode(floor(c.repair_date-e.startdate),34,count(*)),
    decode(floor(c.repair_date-e.startdate),35,count(*)),decode(floor(c.repair_date-e.startdate),36,count(*)),
    decode(floor(c.repair_date-e.startdate),37,count(*)),decode(floor(c.repair_date-e.startdate),38,count(*))
     from  tm_sst a,tm_rssc b,tt_activity_vehicle c,ti_workitem_detail
    d,tm_recall_activity e
    where c.operate_sst_code=a.sst_code
    and a.rssc_id=b.rssc_id
    and e.recall_activity_id=c.recall_activity_id
    and
    e.activity_code='L001'
    and d.labor_no in
    ('MFJC0000','WXBY0000','WXBY1000','JCWB0000','JWBL0000','LP000000','JCDQ0000')
    and c.operate_sst_code=d.sst_code and c.bill_no=d.bill_no
    group by b.rssc_name,(c.repair_date-e.startdate),d.labor_no order by
    b.rssc_name,d.labor_no,floor(c.repair_date-e.startdate);
     
    ----------------------------------------------------------------------------------------------------------------------------
    结果是
    第一行
    辽宁分销中心
    JCDQ0000         0
    0
    0
    0
    0
    0
    0
    0
    0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     1
    第二行
    辽宁分销中心
    MFJC0000         0
    1
    0
    0
    0
    0
    0
    0
    0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     0
     
    直接COPY的结果,没有修改,大家看起来可能困难些,见量吧。里面SQL也没修改,以后有时间再写个明白的吧
     
     
    =======================================================
    类似

    CREATE OR REPLACE  PACKAGE PKG_JCCTEST1                          
    AS

      type rc_class is ref cursor;

    。。。。。。。。。。。。。。

    procedure GetSubAndSum2(p1 number,p2  number ,
                  ResultCursor out rc_class);

    程序调用'{call PKG_JCCTEST1.GetSubAndSum2(?,?)}'
    ==========================================================
    以下是COPY别人JAVA的脚本。

    CREATE OR REPLACE PACKAGE TESTPACKAGE  AS

     TYPE Test_CURSOR IS REF CURSOR;

    end TESTPACKAGE;

     

    CREATE OR REPLACE PROCEDURE TESTC(p_CURSOR out TESTPACKAGE.Test_CURSOR) IS

    BEGIN

        OPEN p_CURSOR FOR SELECT * FROM HYQ.TESTTB;

    END TESTC;

     

    package com.hyq.src;

    import java.sql.*;

    import java.io.OutputStream;

    import java.io.Writer;

    import java.sql.PreparedStatement;

    import java.sql.ResultSet;

    import oracle.jdbc.driver.*;

     

     

    public class TestProcedureTHREE {

      public TestProcedureTHREE() {

      }

      public static void main(String[] args ){

        String driver = "oracle.jdbc.driver.OracleDriver";

        String strUrl = "jdbc:oracle:thin:@127.0.0.1:1521:hyq";

        Statement stmt = null;

        ResultSet rs = null;

        Connection conn = null;

     

        try {

          Class.forName(driver);

          conn =  DriverManager.getConnection(strUrl, "hyq", "hyq");

     

          CallableStatement proc = null;

          proc = conn.prepareCall("{ call hyq.testc(?) }");

          proc.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);

          proc.execute();

          rs = (ResultSet)proc.getObject(1);

     

          while(rs.next())

          {

              System.out.println("<tr><td>" + rs.getString(1) + "</td><td>"+rs.getString(2)+"</td></tr>");

          }

        }

        catch (SQLException ex2) {

          ex2.printStackTrace();

        }

        catch (Exception ex2) {

          ex2.printStackTrace();

        }

        finally{

          try {

            if(rs != null){

              rs.close();

              if(stmt!=null){

                stmt.close();

              }

              if(conn!=null){

                conn.close();

              }

            }

          }

          catch (SQLException ex1) {

          }

        }

      }

    }

    在这里要注意,在执行前一定要先把oracle的驱动包放到class路径里,否则会报错的。

    ACCESS导入到ORACLE

     昨天去甲方导数据,去之前居然没人知道要导什么,内容是什么,去了一看,ACCESS库,240W条数据,文件有740M,

    最初建立ODBC,直接用ACCESS 导入到ORACLE。但由于字符集的问题(UTF8)导致导入失败,因为UTF8用3字节存放汉字,而导库过程是由ACCESS按自己的定义自动建立ORACLE表的,如果事先在ORACLE里建立表,然后导入会得到对象已存在的错误。为解决此问题,想在ACCESS中修改字段长度,但是由于数据量过大,导致WIN OS报内存或磁盘空间满的问题,按WIN的提示去修改注册表及释放空间等,皆解决不了问题,而由于数据量较大,浪费了很多时间。

    采取第二种方案SQLLDR,用ACCESS打开,然后保存成TXT文件,以逗号分割。打包压缩,FTP到服务器上,运行SQLLDR,结果报如下错误:
    SQL*Loader: Release 9.2.0.6.0 - Production on Wed Apr 26 16:31:29 2006

    Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.
    Segmentation fault(coredump)
     从头狼处得到解释,
    fact: Oracle Server - Enterprise Edition 9.2
    fact: SQL*Loader
    fact: AIX-Based Systems
    symptom:
    Segmentation Fault (coredump)
    symptom: Log file is not written
    symptom: Stack trace: waitpid sntpreap sslsshandler
    thread_tsleep
    symptom: SQL*Loader fails at the end of load
    cause: Operating System defect
    fix:
    1. Install the following
    fixes specific to AIX version:
       a. AIX 4.3.3: IY30151,IY30927
       b. AIX 5.1(5L): IY30150
    2. and relink SQL*Loader
    executable:
       a. $ cd $ORACLE_HOME/rdbms b
       b. $ make -f ins_rdbms.mk isqlldr
    由于权属问题,不好对OS操作,所以这个方法也放弃。

    采用第三个方案,建立一个ZHS16GBK的数据库,先将ACCESS的数据到入到这个中间库中,然后修改字段长度,再导入到正式库中,成功。实际这个方案早在考虑当中,只是我的本子有两个库都是UTF8的,最后痛下决心,删了一个库,然后建立ZHS16GBK的数据库。
           导库过程随时都会遇到这样那样的问题,因此及时修改方案,及时评估成本,而不应该一条道走到黑

     

    SELECT FOR UPDATE 相关的知识

       单位里最大连接数很低,但由于历史原因,居然每个dml操作前都要SELECT FOR UPDATE一下,因此会造成LOCK的问题,写此文仅给一些常用FOR UPDATE的人。
            statement: 一个SQL语句。
            session:     一个由ORACLE用户产生的连接,一个用户可以产生多个SESSION ,但相互之间是独立的。
            transaction:所有的改变都可以划分到transaction里,一个transaction包含一个或多个SQL。当一个SESSION建立的时候就是一个TRANSACTION开始的时刻,此后transaction的开始和结束由DCL控制,也就是每个COMMIT/ROLLBACK都标示着一个transaction的结束。
            consistency:是对于statement级别而不是transaction级别来说的。sql statement 得到的数据都是以sql statement开始的IMAGE。
     
            LOCK的基本情况
    update, insert ,delete, select ... for update会LOCK相应的ROW 。
    只有一个TRANSACTION可以LOCK相应的行,也就是说如果一个ROW已经LOCKED了,那就不能被其他TRANSACTION所LOCK了。
    LOCK由statement产生但却由TRANSACTION结尾(commit,rollback),也就是说一个SQL完成后LOCK还会存在,只有在COMMIT/ROLLBACK后才会RELEASE。
     
            SELECT.... FOR UPDATE [OF cols] [NOWAIT];
    OF cols
    SELECT cols FROM tables [WHERE...] FOR UPDATE [OF cols] [NOWAIT];
    前面的FOR UPDATE就不说了,讲下OF
    transaction A运行
    select a.object_name,a.object_id from wwm2 a,wwm3 b
      2     where b.status='VALID' and a.object_id=b.object_id
      3*   for update of a.status
    则transaction B可以对b表wwm3的相应行进行DML操作,但不能对a表wwm2相应行进行DML操作.
    反一下看看
    transaction A运行
    select a.object_name,a.object_id from wwm2 a,wwm3 b
      2     where b.status='VALID' and a.object_id=b.object_id
      3*   for update of b.status
    则transaction B可以对a表wwm2的相应行进行DML操作,但不能对b表wwm3相应行进行DML操作.
    也就是说LOCK的还是行,只是如果不加OF的话会对所有涉及的表LOCK的,加了OF后只会LOCK OF 字句所在的TABLE.
    NOWAIT(如果一定要用FOR UPDATE,我更建议加上NOWAIT)
    当有LOCK冲突时会提示错误并结束STATEMENT而不是在那里等待.返回错误是"ORA-00054: resource busy and acquire with NOWAIT specified"
     
    另外如下用法也值得推荐,应该酌情考虑使用。
    FOR UPDATE WAIT 5
    5秒后会提示ORA-30006: resource busy; acquire with WAIT timeout expired
    FOR UPDATE NOWAIT SKIP LOCKED;
    会提示no rows selected
     
            TABLE  LOCKS
     LOCK TABLE table(s) IN EXCLUSIVE MODE [NOWAIT];
    同样也是在transaction结束时才会释放lock。
     
            DEADLOCK
    transaction a lock rowA     ,  then  transaction b lock rowB
    then transaction a tries to lock rowB, and transaction b tries to lock rowA
    也就是说两个transaction都相互试图去lock对方已经lock的ROW,都在等待对方释放自己的lock,这样就使死锁。
    deadlock也会有600提示。

    CVS安装及权限分配

    2.安装过程

    2.1        解压

    #tar xvf cvsnt-2.5.03.2151-rh9-rpm.tar.tar

    2.2        包的安装

    rpm -ivh cvsnt-2.5.03.2151-1.i386.rpm  

    2.3        建立Repository目录

    groupadd cvs

    useradd -G cvs cvsroot

    mkdir /home/cvsroot

    chown -R cvsroot.cvs /home/cvsroot

     

    /etc/xinetd.d/ cvspserver

    service cvspserver

    {

            disable = no

            socket_type     = stream

            wait            = no

            port            =2401

            user            = root

            env             = HOME =

            server          = /usr/bin/cvs

            server_args     = -f   --allow -root=/home/cvshome pserver

    }

    重起#service xinetd restart 使配置生效。 

    2.4        设置环境变量

    #vi .bash_profile

    加入一行CVSROOT=:pserver:cvsroot@192.168.1.29:/home/cvsroot

    *pserver是访问方式,口令认证的意思,这是最常用的方式,其他还有gserver,kserver,ext
    *user
    CVS服务器的用户名,

    *server
    CVS服务器的名称或者IP地址

    */home/cvsroot
    是你的CVS服务器的CVSROOT目录,根据你的CVS服务器设置做修改或者询问管理员

    你可以把设置放到你的shellprofile里(.bash_profile.profile等)这样就不用每次敲一长串命令了

    2.5        验证配置成功 

    #cvs login,输入密码看时候能成功登录

    2.6        初始化repository

    cvs    -d /home/cvsroot init

    2.7          CVS使用流程
       a checkout 尽当本地没有working copy时使用
       b staus
    检查服务器上是否有新版本
       c update
    如果有,则用update同步文件
       d 
    做你自己的修改,并保证正确
       e update
    看是否有人修改了你的文件
       f 
    如果有冲突,合并冲突
       g commit
    提交你的修改,如果因为又有人提交修改而失败,回到e
       h 
    回到b

    3         管理内容

    3.1        建立REPOSITORY

    Su – cvsroot

    cvs -d /opt/cvsroot/project1 init

    3.2        建立MODEL

    Su - cvsroot

    cvs -d /opt/cvsroot/project1 import wwm3model vendor_version release_100 

    会在project1下建立wwm3model,并且将运行cvs –d的目录内的所有内容作为model的内容。vendor_version release_100是相应的版本

    3.3        CHECK OUT

    Su – vcsroot

    Cvs –d /opt/cvsroot/project1 checkout wwm3model

    3.4        权限设置

    权限方面可以脱离OS用户权限而独立存在,可以按PROJECT来区分不同用户读写权限

    得到密码

    cvspasswd yourpass

    REPOSITORY下有三个文件(初始并没有这三个文件,需要自己建立)

    Passwd ,readers, writers

    Passwd 密码文件,内容形如:

    info1:zb720xIK.Cmcs:cvsroot

    qwer:nxqg.qgAKcMZg:cvsroot

    owner:nxqg.qgAKcMZg:cvsroot

    wwm5:pUCT2qT6E334U:cvsroot

    第一列是要分配给使用者的用户名,第二列是通过cvspasswd加密的密码,第三列是OS CVS用户

           Readers只读用户文件,内容如下:

                  info1

    qwer

    owner

    readers文件结构和writers一样,都是由用户名组成的单列,在这里的用户有读的权限

           writers可写用户文件,内容如下

                  wwm5

                  writers文件结构和readers一样,都是由用户名组成的单列,在这里的用户有读写的权限

    3.5        权限深入,按MODULE区分

    [root@cvshost CVSROOT]# vi passwd

     

    test1:HH9dq1sQ.9TPQ:cvsroot

    test2:HH9dq1sQ.9TPQ:userpro7

    test3:HH9dq1sQ.9TPQ:news

    userpro7cvsroot同组注意,这次没有做readerswriters两文件

    [cvsroot@cvshost cvsroot]$ ls -alt /opt/cvsroot/          --repositoryOS权限

    drwxr-xr-x  5 cvsroot cvsroot 4096  4? 5 16:33 project7

    [cvsroot@cvshost project7]$ ls -alt /opt/cvsroot/project7    ---moduleOS权限

    drwxrwxr-x  3 cvsroot cvsroot 4096  4? 5 17:05 userpro7mo

    dr-xr-xr-x  4 cvsroot cvsroot 4096  4? 5 17:01 CVSROOT

    drwxr-x---  7 cvsroot cvsroot 4096  4? 5 16:43 cvsrootproj7

     

    userpro7mo

    R

    w

    Test1

    Y

    Y

    Test2

    Y

    Y

    Test3

    Y

    N

     

    cvsrootproj7

    R

    w

    Test1

    Y

    Y

    Test2

    Y

    N

    Test3

    N

    N

    CVS简介

    1          CVS简介

    1.1        定义与优点

    CVS (Cuncurrent Versions System)是基于TCP/IP协议的版本控制工具。CVS是一个并行版本控制系统,它采用C/S模式,它的复杂度和功能性属于中等,是当今最流行的版本控制系统。它有两个基本的特点:
        *
    保存修改记录:保存了所有文件的修改历史,并可以建立分支

        *
    协作与并行:cvs不推荐使用lock-modify-unlock的串行的工作模式,而采用多人可以并行地修改同一个文件,而在提交时merge conflict;它更适合于大型的工作团体。

    使用CVS的好处:

        *
    文件集中管理,大家都可以方便的看到所有人员的最新文件,规范化了文件的管理

        *
    可以查看以前任何的一个版本或修改历史

        *
    可以同时维护多个版本和分支

    和在Windows 开发平台中拥有很大用户群的Visual Source Safe(VSS)相比,CVS主要由两个不同之处。

    一是VSS依靠服务器上的一个共享目录提供服务,每一个client必须能够访问这个共享目录。这也就决定了source safeTCP/IP环境下使用很困难。对于分布跨越数个城市甚至国家的工作小组来说,只有通过VPN才能够安全的访问source safe数据库。而CVS依靠TCP/IP连接提供服务,所以它天生就是为了在internet上协同工作而设计的。

    二是CVS反对对文件上锁的机制。VSS以及其他很多传统版本控制工具要求一个文件只能有一个使用者,它必须先checkout声明编辑文件的独享权力,直到checkin为止。但是对于地理上不限制使用者位置的CVS来说,等待一个用户checkin是一件痛苦的事情,而互相沟通比一个紧密工作的团体更困难。CVS采取多个用户可以同时对一个文件进行编辑,然后commit的方式解决这个问题。假设由于沟通不足出现冲突,使用者必须手工解决冲突之后再进行commit。在这种情况下,冲突的开发者必须努力进行足够的沟通以避免再次冲突。

    1.2        repository项目包,module

    CVS服务器上,一个源代码仓库被称为一个repository,一个server上通常可以运行多个repository,每个repository都是完全独立的,可以有不同的用户列表和访问规则。在一个repository之下,文件按照module组织,每一个module就相当于一个工程,大致上相当于Source safe里面的project

    VSS在你连接上服务器之后,会列出所有的project。但并不是所有的CVS server都会提供module的列表。事实上,哪些module被公开是由管理员控制的。如果你知道一个被隐藏的module的名字,你仍然可以正常的访问这个module

    1.3        CVSROOT代码库

    CVS依靠运行在服务器上的一个服务程序提供TCP/IP的连接。为了访问一个CVS数据库,你必须知道你所使用的协议,服务器的地址,服务器提供的Repository的名称以及你的用户名和密码。

    有数种协议可供选择。Unix/Linux机器上的CVS通常使用pserver协议。除此之外,NT机器还支持ntserver协议,它通过主机的NT用户表进行访问控制(但是这是在internet上不可用的方法)。kservergserver协议用的比较少,他们依据Kerboses提供额外的安全保护。

    你有必要知道CVSROOT这个参数。CVSROOT是一个用":"开始及分隔各个部分的字符串,它包含了协议、用户名、服务器地址和repository名称。对于用户来说,CVSROOT就像URL一样,是访问一个server的途径。

    一个典型的CVSROOT=:pserver:cvsroot@192.168.1.29:/home/cvsroot。这里,pserver是协议名称,cvsroot是用户id192.168.1.29是主机ip, /home/cvsrootrepository的名字。NT主机的repository一般会采取d:/CVSROOT之类的格式。

    windows下使用命令行方式,这个参数可以通过一个环境变量使用。在windows 2000/XP系统中,你可以通过在'My computer'properties中选择advanced,然后选择'Enviroment Variables'来输入这个环境变量。

    1.4        checkout,update

    为了得到module下面的源代码,你只需要使用checkout指令。和Visual source safe不一样,checkout只是取得文件,而非锁文件。

    如果你已经有了本地文件,为了和server保持同步,你需要进行update操作。update会自动把server上的新内容取到本机来,如果你本地文件进行过了改动,它会帮您做合并工作。

    checkout update既可以针对一个特定的文件,也可以针对一个目录或者整个module

    1.5        commit

    如果你对本地代码做了任何修改,或者增加一个文件,删除一个文件,每当你需要把你的改变提交到server上的时候,你就需要做commit动作。假设两个人都在本地修改了同一个文件,那么他们就像在进行一个竞赛,如果你快,那么你赢了。后commit的人将被server拒绝,不得不合并你的修改再次提交。

    commit既可以针对一个特定的文件,也可以针对一个目录或者整个module

    1.6        revision

    Revision是指每一个文件的版本信息。当你第一次增加一个文件到repository的时候,它会有一个初始revision1.1,以后每次提交,就会增加到1.2,1.3...

    在一个branch中的文件,有相对于这个branch的版本号。如果你对文件作了tag,那么你会看到revision变成1.1.1.1的形式。具体的含义我们在branchtag的时候描述。

    1.7        branch

    Branch是一棵正常生长的代码树中的枝杈。开始的时候,任何一个module都有一个主枝被称为'HEAD'

    一个branch最终要么被合并到主干中去,要么被结束。branch通常用来debug,如果这个bugfix了,修改bug的代码应该被合并到主枝上去。一个branch也可能经历多次与主枝的合并。

    1.8        tag

    Tag用来进行标示必要的信息。当您进行一次公开发布之前,您有必要对主枝标示"release 1.0"。这样您以后就可以随时回到这个版本。

     

    2       

    一次不让发那么多,只好分两次发了

    ORACLE 内存管理 之二 PGA v$pgastat

    • PGA 自动管理

               需要设置两个基本点参数 :

    WORKAREA_SIZE_POLICY=AUTO,默认就是AUTO

    PGA_AGGREGATE_TARGET总的PGA的大小

               注意,9Ishared server连接需要明确设置SORT_AREA_SIZE HASH_AREA_SIZE,也就是说不能用自动管理模式。10G则无此限制。

               PGA_AGGREGATE_TARGET是一个上限(理论上的最大值,PL/SQL就很容易超过),ORACLE启动时并不分配那么多,你甚至可以设置大于物理MEM的大小(生产库不要这么做呀,要设置pga_aggregate_target+sga<MEM ,别挑战ORACLE的极限)。一个SESSION可能有多个sort,hashworkarea,每一个workarea最多会用到5%100M(由两个隐藏参数控制),因此如果预计每个sort,hashworkarea5M,应该设置PGA_AGGREGATE_TARGET100M。但是,随着用户的增加或工作量的增大,给每个workarea的容量可能会减少,因为有总量PGA_AGGREGATE_TARGET的限制,比如需要100workarea,那么每个只能分配到1Mparallel query会用到最多30%(由隐藏参数控制)PGA_AGGREGATE_TARGET,每一个parallel queryPIECE会分配相应的30%,也就是parallel query可能会用到30M10PARALLEL,那么每个用3M。这也就是建议用auto管理的原因,一个系统通常workload,session是随时间变化的,早上可能3个用户,中午可能300个用户,所以用固定sort,hash的参数是不合时宜的.自动管理才可以实现在用户并发少的时候分配更多的内存,在并发多的时候照顾大众,分配少的内存。ORACLE 9.2以后有了PGA advisory

    • v$pgastat

    SQL> show parameter pga

     

    NAME                                 TYPE                   VALUE

    ------------------------------------ ---------------------- ------------------------------

    pga_aggregate_target                 big integer            105906176

     

    SQL> show parameter workarea

     

    NAME                                 TYPE                   VALUE

    ------------------------------------ ---------------------- ----------

    workarea_size_policy                 string                 AUTO

     

      1  select name||' '||

      2          to_char(decode( unit,

      3                    'bytes', value/1024/1024,

      4                             value ),'999,999,999.9')||' '||

      5           decode( unit, 'bytes', 'mbytes', unit )

      6*   from v$pgastat

    SQL> /

     

    NAME||''||TO_CHAR(DECODE(UNIT,'BYTES',VALUE/1024/1024,VALUE),'999,999,999.9')||''||DECODE(UNIT,'BYTE

    ----------------------------------------------------------------------------------------------------

    aggregate PGA target parameter          101.0 mbytes

    aggregate PGA auto target           74.1 mbytes

    global memory bound            5.0 mbytes

    total PGA inuse           22.0 mbytes

    total PGA allocated           33.2 mbytes

    maximum PGA allocated           33.4 mbytes

    total freeable PGA memory             .0 mbytes

    PGA memory freed back to OS             .0 mbytes

    total PGA used for auto workareas            3.3 mbytes

    maximum PGA used for auto workareas            4.8 mbytes

    total PGA used for manual workareas             .0 mbytes

    maximum PGA used for manual workareas            3.6 mbytes

    over allocation count             .0

    bytes processed        1,545.8 mbytes

    extra bytes read/written           75.1 mbytes

    cache hit percentage           95.4 percent

     

    解释

    aggregate PGA auto target         74.1 mbytes,可以使用的PGA,也就是说剩余的PGA 

    total PGA inuse           22.0 mbytes                    现在使用的PGA

    over allocation count             .0                           ORACLE分配的PGA超过pga_aggregate_target  的次数.这个参数可以判断pga_aggregate_target 是否设置的太小.

    cache hit percentage                           95.4 percent           自从instance启动后的PGA 命中率,如果所有的操作都在MEM中进行没有在TEMP里运行的话应该是100%.

    ORACLE内存管理 之三 PGA v$sql_workarea_histogram v$pga_target_advice

     

    另外还有一个很重要的试图来观察PGA的效率v$sql_workarea_histogram

    pga_aggregate_target                 big integer              1236648591

      1  SELECT

      2       case when low_optimal_size < 1024*1024

      3            then to_char(low_optimal_size/1024,'999999') ||

      4                 'kb <= PGA < ' ||

      5                 (HIGH_OPTIMAL_SIZE+1)/1024|| 'kb'

      6            else to_char(low_optimal_size/1024/1024,'999999') ||

      7                 'mb <= PGA < ' ||

      8                 (high_optimal_size+1)/1024/1024|| 'mb'

      9            end ||' '||

     10           optimal_executions||' '||

     11           onepass_executions||' '||

     12           multipasses_executions

     13      from v$sql_workarea_histogram

     14     where total_executions <> 0

     15*    order by low_optimal_size

    SQL> /

     

    CASEWHENLOW_OPTIMAL_SIZE<1024*1024THENTO_CHAR(LOW_OPTIMAL_SIZE/1024,'999999')||'

    --------------------------------------------------------------------------------

         16kb <= PGA < 32kb             53646550               0                0

         32kb <= PGA < 64kb             26062               0                0

         64kb <= PGA < 128kb             20361               0                0

        128kb <= PGA < 256kb             893               0                0

        256kb <= PGA < 512kb             941               0                0

        512kb <= PGA < 1024kb             8331               0                0

          1mb <= PGA < 2mb             1836               0                0

          2mb <= PGA < 4mb             505               0                0

          4mb <= PGA < 8mb             218               4                0

          8mb <= PGA < 16mb             294               8                0

         16mb <= PGA < 32mb             261               16                0

     

    CASEWHENLOW_OPTIMAL_SIZE<1024*1024THENTO_CHAR(LOW_OPTIMAL_SIZE/1024,'999999')||'

    --------------------------------------------------------------------------------

         32mb <= PGA < 64mb             51               8                0

         64mb <= PGA < 128mb             5               6                2

        128mb <= PGA < 256mb             0               6                52

        256mb <= PGA < 512mb             0               24                59

        512mb <= PGA < 1024mb             1               2                0

     

    PGA workarea去分析. 32mb <= PGA < 64mb             51               8                0 表示workarea32m-64m 之间的在内存里运行的有51,8次需要用到一次disk,0次多次用到disk.

    128mb <= PGA < 256mb             0               6                52,为什么不用MEM而用DISK,因为每一个PGA PIECE最多只能是PGA_AGGREGATE5%(估计),所以大于这部分的就只能用DISK.

     

    v$pga_target_advice

    1  select

      2    trunc(pga_target_for_estimate/1024/1024)

      3                             pga_target_for_estimate,

      4    to_char(pga_target_factor * 100,'999.9') ||'%'

      5                             pga_target_factor,

      6    trunc(bytes_processed/1024/1024) bytes_processed,

      7    trunc(estd_extra_bytes_rw/1024/1024) estd_extra_bytes_rw,

      8    to_char(estd_pga_cache_hit_percentage,'999') || '%'

      9                              estd_pga_cache_hit_percentage,

     10    estd_overalloc_count

     11*   from v$pga_target_advice

    SQL> /

     

    PGA_TARGET_FOR_ESTIMATE PGA_TARGET_FAC BYTES_PROCESSED ESTD_EXTRA_BYTES_RW

    ----------------------- -------------- --------------- -------------------

    ESTD_PGA_C ESTD_OVERALLOC_COUNT

    ---------- --------------------

                        147   12.5%                1074286              211218                84%                        44

                        294   25.0%                1074286              180162                86%                         0

                        589   50.0%                1074286              170085                86%                         0

                        884   75.0%                1074286              168992                86%                         0

                                    1179   100.0%                    1074286                   167579                               87%                         0

                       1415  120.0%                1074286               51551      95%                         0

                       1651  140.0%                1074286               51551      95%                         0

                       1886  160.0%                1074286               51380      95%                         0

                       2122  180.0%                1074286               51186      95%                         0

                       2358  200.0%                1074286               51186      95%                         0

                       3538  300.0%                1074286               51186      95%                         0

                       4717  400.0%                1074286               51186      95%                         0

                       7076  600.0%                1074286               51186      95%                         0

                       9434  800.0%                1074286               51186      95%                         0

    可以看到统计数据表现这个库有很大的问题.现在是1179M, estd_pga_cache_hit_percentage=87%,即便将PGA_TARGET扩大到8倍命中率还是不高95%.(会在以后的文章里修改次问题的)

    当你重新设置pga_aggregate_target后这个view的数据会重新开始.