다음은 일반 테이블을 partition table로 online redefinition기능을 이용해 변경하는 예제입니다. 

SCOTT.EMP_REDEF table은 HIREDATE가 varchar2로 정의되어 있는데, 
partition table을 day interval로 하기 위해서 HIREDATE를 date type으로 바꿔줘야 합니다. 
online redefinition 기능을 이용해서 HIREDATE column 값을 이용해 hir_date 라는 date column을 추가하고 
partition으로 변경합니다.

1. table 생성 및 데이터 입력

CREATE TABLE SCOTT.EMP_REDEF
(EMPNO NUMBER(4) NOT NULL,
ENAME VARCHAR2(10),
JOB VARCHAR2(9),
MGR NUMBER(4),
HIREDATE varchar2(8),
SAL NUMBER(7, 2),
COMM NUMBER(7, 2),
DEPTNO NUMBER(2)) tablespace USERS;

alter table SCOTT.emp_REDEF add constraint emp_pk primary key (empno);

INSERT INTO SCOTT.EMP_REDEF VALUES (7369, 'SMITH', 'CLERK', 7902,'20100415', 800, NULL, 20);
commit;

2. redefinition 가능 여부 판단. 
exec dbms_redefinition.can_redef_table('SCOTT', 'EMP_REDEF');

3. 임시 table 생성 
create table scott.emp_REDEF2
    (empno number primary key,
    ename varchar2(10),
    designation varchar2(9),
    mgr number(4),
    hiredate varchar2(8),
    hir_date date,
    sal number(7,2),
    comm number(7,2),
    deptno number(2)
    ) 
partition by range (hir_date) interval (numtodsinterval(1,'DAY'))
( partition p_before_1_jan_2005 values  less than (to_date('20050101','yyyymmdd')))
tablespace USERS
/

4. redefinition 지정.
alter session set nls_date_format = 'yyyymmdd';
exec dbms_redefinition.start_redef_table('SCOTT','EMP_REDEF','EMP_REDEF2', 'EMPNO EMPNO, ENAME ENAME, JOB DESIGNATION, MGR MGR, HIREDATE HIREDATE, to_date(hiredate) hir_date, SAL SAL,COMM COMM,DEPTNO DEPTNO');

5. data sync
exec dbms_redefinition.sync_interim_table('SCOTT','EMP_REDEF','EMP_REDEF2');

6. finish 
exec dbms_redefinition.finish_redef_table('SCOTT','EMP_REDEF','EMP_REDEF2');

7. 임시 table 삭제. 
drop table scott.emp_REDEF2;

8. 원본 데이터 변경 확인. 

SQL> select * from scott.emp_REDEF;

     EMPNO ENAME                          DESIGNATION                        MGR HIREDATE                 HIR_DATE        SAL       COMM     DEPTNO
---------- ------------------------------ --------------------------- ---------- ------------------------ -------- ---------- ---------- ----------
      7369 SMITH                          CLERK                             7902 20100415                 20100415        800                    20

SQL> desc scott.emp_REDEF
 Name                                                                                                              Null?    Type
 ----------------------------------------------------------------------------------------------------------------- -------- ----------------------------------------------------------------------------
 EMPNO                                                                                                             NOT NULL NUMBER
 ENAME                                                                                                                      VARCHAR2(10)
 DESIGNATION                                                                                                                VARCHAR2(9)
 MGR                                                                                                                        NUMBER(4)
 HIREDATE                                                                                                                   VARCHAR2(8)
 HIR_DATE                                                                                                                   DATE
 SAL                                                                                                                        NUMBER(7,2)
 COMM                                                                                                                       NUMBER(7,2)
 DEPTNO                                                                                                                     NUMBER(2)

SQL> select table_name,PARTITION_NAME,HIGH_VALUE from dba_tab_partitions where table_name = 'EMP_REDEF';

TABLE_NAME                                                                                 PARTITION_NAME
------------------------------------------------------------------------------------------ -----------------------------------------
HIGH_VALUE
--------------------------------------------------------------------------------
EMP_REDEF                                                                                  P_BEFORE_1_JAN_2005
TO_DATE(' 2005-01-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA

EMP_REDEF                                                                                  SYS_P41
TO_DATE(' 2010-04-16 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIA




* 여기저기서 좋다는 책 몇권 추천합니다. 고수가 되는 그날까지.. 파이팅!!



Oracle Database Migration이나 데이터 정리 등을 하려 TRUNCATE 명령 등을 수행할 때 ORA-2266에러를 만날 수 있습니다. 
요 에러는 reference constraint key가 걸려 있어 명령을 수행할 수 없다는 에러인데, 내가 작업하려 하는 table의 PK를 누가 참조하고 있다는 의미죠. 

> oerr ora 2266
02266, 00000, "unique/primary keys in table referenced by enabled foreign keys"
// *Cause: An attempt was made to truncate a table with unique or 
//         primary keys referenced by foreign keys enabled in another table.
//         Other operations not allowed are dropping/truncating a partition of a
//         partitioned table or an ALTER TABLE EXCHANGE PARTITION.
// *Action: Before performing the above operations the table, disable the 
//          foreign key constraints in other tables. You can see what 
//          constraints are referencing a table by issuing the following 
//          command:
//          SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME = "tabnam";

이런 경우 dba_constraints를 query해서 어떤 table에서 reference 하고 있는지 확인할 수 있습니다. 
간단한 SQL이지만 계속 만들기 귀찮아 한번 정리해 봅니다. 

column r_owner format a20
column r_constraint_name format a30
column owner format a20
column table_name format a30
column constraint_name format a30
column "Constraint Disable COMMAND" format a150
set linesize 200
set pagesize 200
select r_owner,r_constraint_name,owner,table_name,constraint_name,constraint_type
from dba_constraints
where r_constraint_name in (select constraint_name from dba_constraints where table_name = upper('&&TABLE_NAME'))
/
select 'alter table '||owner||'.'||table_name||' disable constraint '||constraint_name||';' "Constraint Disable COMMAND"
from dba_constraints
where r_constraint_name in (select constraint_name from dba_constraints where table_name = upper('&TABLE_NAME'))
/

위의 SQL을 돌리면 아래 처럼 reference 하고 있는 table과 해당 constraint가 나옵니다. 
또 요놈들을 disable 해 줄 수 있는 명령도 같이 출력하게 됩니다. 

R_OWNER              R_CONSTRAINT_NAME              OWNER                TABLE_NAME                     CONSTRAINT_NAME                CON
-------------------- ------------------------------ -------------------- ------------------------------ ------------------------------ ---
DBSNMP               BSLN_BASELINES_PK2             DBSNMP               BSLN_STATISTICS                BSLN_STATISTICS_FK             R
DBSNMP               BSLN_BASELINES_PK2             DBSNMP               BSLN_THRESHOLD_PARAMS          BSLN_THRESHOLDS_FK             R

Constraint Disable COMMAND
------------------------------------------------------------------------------------------------------------------------------------------------------
alter table DBSNMP.BSLN_STATISTICS disable constraint BSLN_STATISTICS_FK;
alter table DBSNMP.BSLN_THRESHOLD_PARAMS disable constraint BSLN_THRESHOLDS_FK;

물론 아래처럼 cascade로 다 disable 시킬 수 있지만, 눈으로 한번 확인하고 작업하는 이 신중함 땜에.. ㅋ

ALTER TABLE dept DISABLE PRIMARY KEY CASCADE;


* 여기저기서 좋다는 책 몇권 추천합니다. 고수가 되는 그날까지.. 파이팅!!



DECODE() Function는 return된 결과가 지정된 값과 동일할 경우 특정 value를 출력해주는 function이다.  DECODE()는 다음과 같은 형태로 사용된다.

DECODE(value, search_value, result, default_value)

위의 decode function은 미리 지정된 value와 search_value가 같을 경우 result를, 그렇지 않은 경우 default_value를 출력한다. 이와 같이 decode()는 SQL에서 PL/SQL없이 IF-THEN-ELSE logic을 구현하고 있다.

다음은 decode()의 간단한 동작 예이다.

SELECT DECODE(1, 1, 2, 3)
FROM dual;

DECODE(1,1,2,3)
---------------
              2


SELECT DECODE(1, 2, 1, 3)
FROM dual;

DECODE(1,2,1,3)
---------------
              3

다음의 예는 more_products table의 available column의 값을 비교해 원하는 string을 출력한다. available column의 값이 'Y'일 경우 "Product is available'을 출력하고, 'Y'가 아닐 경우 'Product is not available"을 출력한다.

SELECT prd_id, available,
   DECODE(available, 'Y', 'Product is available',
      'Product is not available')
FROM more_products;

    PRD_ID A DECODE(AVAILABLE,'Y','PR
---------- - ------------------------
         1 Y Product is available
         2 Y Product is available
         3 N Product is not available
         4 N Product is not available
         5 Y Product is available

다음은 product table의 product_type_id column의 값들에 따라 원하는 string을 출력한다. 즉 product_type_id가 1일 경우 'Book', 2일 경우 'Video', 3일 경우 'DVD', 4일 경우 'CD', 기타 다른 값일 경우 'Magazine'을 출력한다.

SELECT product_id, product_type_id,
 DECODE(product_type_id,
   1, 'Book',
   2, 'Video',
   3, 'DVD',
   4, 'CD',
   'Magazine')
FROM products;

PRODUCT_ID PRODUCT_TYPE_ID DECODE(P
---------- --------------- --------
         1               1 Book
         2               1 Book
         3               2 Video
         4               2 Video
         5               2 Video
         6               2 Video
         7               3 DVD
         8               3 DVD
         9               4 CD
        10               4 CD
        11               4 CD
        12                 Magazine

Decode()은 CASE문에 비해 depth가 깊어지면 성능이 떨어지는 것으로 알려져 있다. depth가 깊은 SQL의 경우 CASE()와의 성능 비교가 필요할 수 있다.


* 여기저기서 좋다는 책 몇권 추천합니다. 고수가 되는 그날까지.. 파이팅!!



Active DataGuard 모니터링하는 SQL script를 만들어 보았습니다.
수행환경은 oracle 11g release 1 입니다.

1. 현재 dataguard 관련 process 모니터링
2. 마지막 전송받은 archived log file
3. Primary와 Standby 간의 GAP, 지연 정보 등

column process format a10
column status format a15
column client_pid format a10
column group# format a10
column name format a60
set linesize 200
alter session set nls_date_format = 'MM/DD HH24:MI:SS';
select PROCESS,PID,STATUS,CLIENT_PROCESS,CLIENT_PID,GROUP#,THREAD#,SEQUENCE#,DELAY_MINS,BLOCK#,BLOCKS from V$MANAGED_STANDBY
where status not in ('IDLE','CLOSING')
order by status
/
select b.NAME,b.DEST_ID, b.THREAD#,b.SEQUENCE#,b.STANDBY_DEST,b.ARCHIVED,b.APPLIED,b.STATUS,b.COMPLETION_TIME
from 
(select thread#,max(sequence#) sequence from V$ARCHIVED_LOG group by thread#) a, v$archived_log b
where a.thread# = b.thread# and a.sequence = b.sequence# 
/
column name format a30
column value format a50
column TIME_COMPUTED format a30
column unit format a30
select * from V$DATAGUARD_STATS
/

PROCESS           PID STATUS          CLIENT_PROCESS           CLIENT_PID GROUP#        THREAD#  SEQUENCE# DELAY_MINS     BLOCK#     BLOCKS
---------- ---------- --------------- ------------------------ ---------- ---------- ---------- ---------- ---------- ---------- ----------
MRP0            11615 APPLYING_LOG    N/A                      N/A        N/A                 1      47741          0     214659    1024000
ARCH             9762 CONNECTED       ARCH                     9762       N/A                 0          0          0          0          0


NAME                                                            DEST_ID    THREAD#  SEQUENCE# STANDBY_D ARCHIVED  APPLIED                     STATUS          COMPLETION_TIM
------------------------------------------------------------ ---------- ---------- ---------- --------- --------- --------------------------- -------------
/ARC2/2_21989_697581426.arc                             1          2      21989 NO        YES       YES                         A               03/23 14:39:46
/ARC3/3_21296_697581426.arc                             1          3      21296 NO        YES       YES                         A               03/23 15:06:36
/ARC1/1_47740_697581426.arc                             1          1      47740 NO        YES       IN-MEMORY               A               03/23 16:05:58


NAME                           VALUE                                              UNIT                           TIME_COMPUTED
------------------------------ -------------------------------------------------- ------------------------------ ------------------------------
apply finish time              +00 00:00:03.5                                     day(2) to second(1) interval   23-MAR-2010 16:24:19
apply lag                      +00 00:00:00                                       day(2) to second(0) interval   23-MAR-2010 16:24:19
estimated startup time         32                                                 second                         23-MAR-2010 16:24:19
standby has been open          N                                                                                 23-MAR-2010 16:24:19
transport lag                  +00 00:00:00                                       day(2) to second(0) interval   23-MAR-2010 16:24:19






서점에서 몇번 오라클 관련 서적을 샀었는데, 많이 실망한 적이 많이 있었습니다.
그때는 오라클에 대해 잘 모를 때였던 거 같은데,
나중에 보니 tablespace를 작업공간이라고 해석해 놓았던 책도 있더군요.. --;

다음의 리스트는 오라클 전문가가 되기 위해 읽을만한 추천책입니다.

물론 이제 막 십년 밖에 안된 야매인 제가 추천해드리는 책은 아니고,
http://oracledoug.com 블로그를 운영하는 "Douglas Ian Burns"라는 사람이 추천한 책입니다.
이분은 자그마치 18년의 경력을 갖고 있다시는 군요..
저도 18년 정도 하면 이분 정도의 공력을 갖을 수 있을까..

걱정입니다.. --;
1. Chris Date's Database In Depth from O'Reilly
2. Oracle Concepts manual
3. Expert One-on One: Oracle Written by Tom Kyte
4. Expert Oracle Database Architecture: 9i and 10g Programming Techniques and Solutions
5. Practical Oracle 8i
6. Cost Based Oracle: Fundamentals
7. Optimizing Oracle Performance
8. Oracle Wait Interface: A Practical Guide to Performance Diagnostics and Tuning
 

원문: http://oracledoug.com/books.html

이분이 한국인이 아니기 때문에 당연히 외국 원서 입니다. ㅋ
국내에 번역 된 책도 많이 있는데, 알라딘에서 찾아 링크 좀 걸까 했는데, 국내에서는 절판이나 품절이 많네요.




널리 알려진 기능이지만 사용하는 방법 sample 입니다.
PC 내에 있는 scrpt 정리하다 삭제 전에 한번 올려 봅니다.
혹시 누군가에겐 필요할까 싶어서 ㅎㅎ
(절대 몇일 동안 oracle post가 없어 올리는 건 아닙니다. --;)

ora102@TEST4:/app/oracle/product/db/rdbms/log> sqlplus scott/tiger

SQL*Plus: Release 10.2.0.3.0 - Production on Sun Aug 3 14:57:17 2008

Copyright (c) 1982, 2006, Oracle.  All Rights Reserved.

Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters, OLAP and Data Mining options

SQL> select * from tab;

TNAME                          TABTYPE  CLUSTERID
------------------------------ ------- ----------
BIN$U4gkooULB1PgQLMKTWwM7A==$0 TABLE
BIN$U4iK63kw1zTgQLMKTWx98g==$0 TABLE
EMP                            TABLE
AAA                            TABLE

SQL>
SQL> show recyclebin
ORIGINAL NAME    RECYCLEBIN NAME                OBJECT TYPE  DROP TIME
---------------- ------------------------------ ------------ -------------------
EMP              BIN$U4iK63kw1zTgQLMKTWx98g==$0 TABLE        2008-08-03:14:32:03
TEST             BIN$U4gkooULB1PgQLMKTWwM7A==$0 TABLE        2008-08-03:14:03:27

SQL>  FLASHBACK TABLE TEST TO BEFORE DROP;

Flashback complete.

SQL> select * from tab;

TNAME                          TABTYPE  CLUSTERID
------------------------------ ------- ----------
BIN$U4iK63kw1zTgQLMKTWx98g==$0 TABLE
TEST                           TABLE
EMP                            TABLE
AAA                            TABLE

SQL> purge recyclebin;

Recyclebin purged.

SQL> select * from tab;

TNAME                          TABTYPE  CLUSTERID
------------------------------ ------- ----------
TEST                           TABLE
EMP                            TABLE
AAA                            TABLE


SQL> drop table test;

Table dropped.

SQL> select * from user_recyclebin;

OBJECT_NAME                    ORIGINAL_NAME                    OPERATION
------------------------------ -------------------------------- ---------
TYPE                      TS_NAME                        CREATETIME
------------------------- ------------------------------ -------------------
DROPTIME               DROPSCN PARTITION_NAME                   CAN CAN
------------------- ---------- -------------------------------- --- ---
   RELATED BASE_OBJECT PURGE_OBJECT      SPACE
---------- ----------- ------------ ----------
BIN$U4juzy+wgKngQLMKTWwgxQ==$0 TEST                             DROP
TABLE                     USERS                          2008-08-03:13:57:59
2008-08-03:14:59:59   15636802                                  YES YES
     56903       56903        56903   

2010/03/30
oracle flashback 기능을 그림과 함꼐 잘 설명해 놓은 post가 있어 링크 겁니다

행복만땅 개발자 :: [오라클 10g] 플래시백의 설정/관리





Oracle EM grid control에서 특정 event가 발생하면 해당 내용을 Critical, Warning으로 구분해서 alert 발생시킵니다. 
이 alert 내용을 mail로 delivery 할수 있고 user PL/SQL을 이용해 다른 여러 응용도 가능합니다. 

다음의 SQL script는 EM에서 발생한 alert message와 alert의 상태, 그리고 이에 대한 delivery 수행이 잘 되었는지 확인하는 방법입니다. 

* Oracle 11g Release 1에 Oracle Grid conrol 10.2.0.5 환경에서 테스트 되었습니다. 

SQL> select TARGET_NAME||' /'||METRIC_NAME||' /'||KEY_VALUE METRIC_NAME,TIMESTAMP,DELIVERED,substr(b.MESSAGE,1,100) message,ALERT_STATE,substr(b.DELIVERY_MESSAGE,1,50) DELIVERY_MESSAGE
from sysman.mgmt_notification_log a, SYSMAN.MGMT$ALERT_NOTIF_LOG b
where a.SOURCE_OBJ_GUID(+) =b.SOURCE_OBJ_GUID
and to_char(TIMESTAMP,'MMDD') = '0311'
-- and target_name = 'LISTENER_PMGT_FLPEME01'
-- and DELIVERED ='Y'
order by TIMESTAMP
/


METRIC_NAME                              TIMESTAMP      DEL MESSAGE                                            ALERT_STAT DELIVERY_MESSAGE
--------------------------------------- -------------- --- -------------------------------------------------- ---------- --------------------------------------------------
TEST /problemTbsp /TS_TEST                03/11 02:07:51 Y   Tablespace [TS_TEST] is [97 percent ] full           Critical   Called PL/SQL procedure SYSMAN.LOGGING_ALERT
TEST /problemTbsp /TS_TEST                03/11 02:09:22 Y   Tablespace [TS_TEST] is [97 percent ] full           Critical   Called PL/SQL procedure SYSMAN.LOGGING_ALERT
TEST /problemTbsp /UNDOTBS1              03/11 02:57:45 Y   Tablespace [UNDOTBS1] is [97 percent ] full        Critical   Called PL/SQL procedure SYSMAN.LOGGING_ALERT
TEST /problemTbsp /UNDOTBS1              03/11 02:59:16 Y   Tablespace [UNDOTBS1] is [97 percent ] full        Critical   Called PL/SQL procedure SYSMAN.LOGGING_ALERT






일반적인 HOT block에 따른 현상이 널리 알려진게 'cache buffer chains' 등의 buffer chain에 대한 latch 입니다. 

다음의 SQL은 cache buffers chains children latch 중 가장 sleep count가 높은 children latch의 ADDR에 어떤 block들이 달려 있는지 확인해
그 block 중 가장 동시 접근이 많은 block을 찾는 SQL 입니다. 

select * from (
select HLADDR,TS#,FILE#,DBABLK,TCH , CHILD#,GETS,MISSES,SLEEPS
from x$bh x, 
    (select * from (
     select CHILD#  ,ADDR,GETS,MISSES,SLEEPS  from v$latch_children where name = 'cache buffers chains' order by 5 desc
                   ) 
     where rownum < 2 ) y
where x.hladdr = y.addr
order by tch desc
) where rownum < 2
/





Oracle global temporary table은 Transaction 내에서 임시로 만들 수 있는 table을 지칭합니다. 
transaction 내부에서 사용하는 것이니 당연히 transaction을 commit/ rollback하면 없어지겠죠. 

"global"이라는 단어가 붙은 이유는 table의 구조는 공유한데서 나오니 않았나 싶습니다. 
같은 global temporary table에 각각의 세션에서 데이터를 insert 하면 서로 다른 값을 보여주게 됩니다. 

Global temporary table 생성 명령은 table 생성명령에 global temporary 만 넣어주면 됩니다. 

create global temporary table test_temp ..

global temporary table을 만든 후 dba_objects에서 query를 해보면 해당 이름으로 object_type이 table이라고 나오긴하나, 
dba_segments에서는 해당 이름의 segment는 없는 것으로 보여줍니다. v$sort_usage를 보니 temp tablespace에 temporary data segment type으로 한덩어리 만들어 놓았군요..






오라클에는 현재 수행 중인 세션을 정리하는 방법이 두가지가 있습니다.

하나는 익히 알고 있는 ALTER SYSTEM KILL SESSION 명령이고 다른 하나는 ALTER SYSTEM DISCONNECT SESSION 명령입니다. 이 두개의 명령은 "ALTER SYSTEM" 명령의 "end_session_clauses"에 속하는 명령입니다.




일반적으로 비정상적인 세션을 정리할 때 alter system kill session 명령을 수행하곤 하는데, kill session 명령은 현재 수행중인 transaction을 바로 정리해 버리죠. 그런데, disconnect session  명령은 현재까지 수행된 transaction은 처리하고 session을 정리할 수 있는 방법입니다.

ALTER SYSTEM KILL SESSION '13, 8' IMMEDIATE;
ALTER SYSTEM DISCONNECT SESSION '13, 8' POST_TRANSACTION;


DISCONNECT SESSION은 dedicated server를 강제로 정리해 현 세션을 disconnect 하게 된다. 세션의 지정은 KILL SESSION 과 마찬가지로 'sid, serial#' 으로 지정한다.

DISCONNECT SESSION 문에는 "POST_TRANSACTION" 과 "IMMEDIATE" option을 지정할 수 있다.

POST_TRANSACTION은 현재 transaction이 수행 중이라면 이 transaction이 끝난 후에 세션을 정리하게 되며, 만약 현재 수행 중인 transaction이 없다면 "KILL SESSION"과 동일한 효과를 갖는다. (근데, "KILL SESSION"절에 IMMEDIATE option은 언제 생긴거람.. ?)









예전 포스트에서 V$ view와 DBA_ view의 차이점에 대해서 언급했었습니다.

v$ view는 memory structure data를 보여주며, dba_ table(?)은 system tablespace 상의 data dictoinary data를 보여줍니다. 10g에서 awr 관련 view들이 만들어져서 dba_hist view 등에서 memory structure statistic data를 system tablespace에 저장해서 보여주기도 하죠.


아래의 v$fixed_view_definition view는 오라클의 fixed view의 description을 보여주는 view 입니다.
아래의 내용은 얼마전 bind 변수 값을 찾을 방법이 없을까 .. 해서 한번 뒤져보느라 query 해본 내용입니다.
역시 그런 방법은 없는 것 같더군요.. --;

SQL> select view_definition from v$fixed_view_definition where view_name = 'GV$SQL_BIND_CAPTURE';

VIEW_DEFINITION
-----------------------------------------------------------------------------------------------------------------------
select INST_ID,                 KQLFBC_PADD,                 KQLFBC_HASH,      
          KQLFBC_SQLID,
KQLFBC_CADD,                 KQLFBC_CHNO,                 substr(KQLFBC_NAME,
1, 30),                 KQLFBC_POS,
          to_number(decode(KQLFBC_DUPPOS, 65535, NULL, KQLFBC_DUPPOS)),        
        KQLFBC_OACDTY,             s
ubstr(KQLFBC_DTYSTR, 1, 15),                 KQLFBC_OACCSI,                
KQLFBC_OACPRE,              KQLFBC_OACSCL
,                 KQLFBC_OACMXL,                 decode(KQLFBC_WCAP, 0, 'NO',
'YES'),                 decode(KQLFBC_WCAP
, 0, to_date(NULL), KQLFBC_LCAP),                 KQLFBC_STRVAL,               
  decode(KQLFBC_WCAP, 0, NULL,
                            sys.sys$rawtoany(KQLFBC_BINVAL, KQLFBC_OACDTY,     
                              KQLFBC
_OACCSF, KQLFBC_OACCSI))          from x$kqlfbc;


* 여기저기서 좋다는 책 몇권 추천합니다. 고수가 되는 그날까지.. 파이팅!!



뻔한 script 지만, 나름 쓸만한 shell script 입니다.
shell로 저장한 후 뒤에 sql script와 interval을 주만 무한 루프..
active session 모니터링용으로는 뭐 GUI tool이 부럽지 않죠.. ㅋ

<사용방법>
rpt <sql script name> <interval(sec)>

<내용>
if [ $# -eq 1 ]
then
 arg2=2
elif [ $# -eq 2 ]
then
 arg2=$2
else
     echo "Usage : rpt sql term";
     exit;
fi

arg1=$1
while true
do
sqlplus -s '/ as sysdba' <<EOF
set linesize 200
set pause off
set pagesize 120
@$arg1
EOF
sleep $arg2
done




Oracle External table은 오라클 외부의 데이터를 내부로 loading해 table 형식으로 보여 줍니다.
Oracle 11g R2에서는 "PREPROCESSOR 절"이 생겨 이 외부 file에 대해 선처리 프로세서를 정의해 줄 수 있습니다.

대부분 외부 SAM file 형식이니 압축해제나 shell을 통한 추출 정도의 선 프로세서를 정의할 수 있겠네요.
잘만 된다면 SAM file 저장하는 공간을 줄일 수 있겠네요.

예 : compress된 데이터를 gunzip을 이용해 압축 해제 후 loading

CREATE TABLE sales_transactions_ext
     (PROD_ID NUMBER, CUST_ID NUMBER, TIME_ID DATE, CHANNEL_ID NUMBER, PROMO_ID NUMBER, QUANTITY_SOLD NUMBER,
      AMOUNT_SOLD NUMBER(10,2), UNIT_COST NUMBER(10,2), UNIT_PRICE NUMBER(10,2))
ORGANIZATION external
 (TYPE oracle_loader DEFAULT DIRECTORY data_file_dir
  ACCESS PARAMETERS
  (RECORDS DELIMITED BY NEWLINE CHARACTERSET US7ASCII
   PREPROCESSOR exec_file_dir:'gunzip' OPTIONS '-c'
   BADFILE log_file_dir:'sh_sales.bad_xt'
   LOGFILE log_file_dir:'sh_sales.log_xt'
   FIELDS TERMINATED BY "|"
   LDRTRIM ( PROD_ID, CUST_ID, TIME_ID DATE(10) "YYYY-MM-DD", CHANNEL_ID, PROMO_ID, QUANTITY_SOLD,
                AMOUNT_SOLD, UNIT_COST, UNIT_PRICE))
location ('sh_sales.dat.gz') )
REJECT LIMIT UNLIMITED;






오라클의 통계정보는 다른 DB나 계정으로 옮겨질 수 있습니다.
개발장비에서 수집된 통계정보를 옮긴다거나, 기존의 운영장비의 통계정보를 migration 할 대상으로 옮겨 동일한 SQL 수행을 유도할 수 있습니다.

다음은 현재 SCOTT 계정의 통계정보를 다른 Database의 SCOTT 계정으로 옮기는 예제입니다.

* statistic 정보 수집 table 생성
SQL> exec dbms_stats.create_stat_table('SCOTT','STATS');

* scott.emp table의 통계정보를 statistic 정보수집 테이블인 STATS로 export
exec dbms_stats.export_table_stats('SCOTT','EMP',NULL,'STATS',NULL,TRUE);

* STATS table export
%exp scott/tiger tables=STATS file=expstat.dmp

* STATS table import
%imp scott/tiger file=expstat.dmp full=y log=implog.txt 

* STATS table의 통계정보를 SCOTT.EMP에 import
exec dbms_stats.import_table_stats('SCOTT','EMP',NULL,'STATS',NULL,TRUE);

기존의 통계정보를 다른 Database의 동일 계정으로 옮기는 작업에 대한 내용들은 많이 기술 되어 있는데,
이름이 다른 계정은 어떻게 옮길까요?

다른 계정으로 통계정보를 옮기는 작업은 다른 데이터베이스내의 동일 계정으로 통계정보를 옮기는 작업처럼 procedure로만은 불가능합니다.
물론 작업 자체가 불가능하다는 이야기는 아닙니다.

You may not export stats from one schema name and import into a different schema name (Bug 1077535). The schema names much match exactly. If the target database schema name (import database) is different from the source database schema name (export database), then you may update the table you exported the statistics into and set the C5 column to the target schema name.

통계정보를 export 받기 전에 생성하는 statistic 정보를 저장하는 stat table에는 통계정보가 만들어진 계정의 이름이 지정되어 있어,
이를 다른 계정으로 import하려고 하면 import는 성공했다고 나오나 통계정보는 입력 되지 않습니다.

따라서 수집된 통계정보가 있는 table의 owner column의 owner를 바꿔줘야 합니다.

i.e.
"update table sd_stat set c5 = '<target schemaname>'
where c5 = '<Source Schema name>'
  and statid = '<Stat Id used while exporting these stats>;"

update sd_stat set c5 = 'JBARLOW';
where c5 = 'SCOTT'
  and statid = 'a';
commit;

정리해 보자면 SCOTT 계정의 SD table의 통계정보를 JBAARLOW 계정으로 옮긴다면 아래와 같이 수행해야 합니다.

* statistic 정보 수집 table 생성
SQL> exec dbms_stats.create_stat_table('SCOTT','SD_STAT');

* scott.sd table의 통계정보를 statistic 정보수집 테이블인 SD_STATS로 export
exec dbms_stats.export_table_stats('SCOTT','SD',NULL,'SD_STAT',NULL,TRUE);

*  SD_STAT table의 계정정보 수정
update sd_stat set c5 = 'JBARLOW';
where c5 = 'SCOTT';
commit;

* STATS table의 통계정보를 JBARLOW.SD table에 import
exec dbms_stats.import_table_stats('JBARLOW','SD',NULL,'SD_STAT',NULL,TRUE,'SCOTT');


참고 : Note 117203.1 How to Use DBMS_STATS to Move Statistics to a Different Database





Oracle INVISIBLE index는 Oracle 11g new feature 입니다.

말 그대로 보이지 않는 index 입니다. 여기서 보는 주체는 oracle optimizer가 됩니다.
즉 index는 존재하지만 optimizer는 이를 기준으로 plan을 생성하지 않습니다.
그러나 해당 index의 table에 대한 DML 변경 내역은 모두 index에 적용되게 됩니다.

이는 index 생성에 따른 혹은 index 삭제에 따른 전체 성능, 일부 성능 측정에 도움이 될 만한 feature가 아닌가 싶습니다.

Invisible index 생성
SQL> Create index invisible_index on table(column) invisible;

Invitible index 사용 정의
SQL> alter session set optimizer_use_invisible_indexes=true;

Invisible index를 visible로 변경
SQL> alter index invisible_index visible;

visible index를 invisible로 변경
SQL> alter index invisible_index invisible;





Oracle과 다른 DB와의 차이점을 보면 굉장히 손이 많이 갑니다.
oracle 10g, 11g가 나오면서 운영의 자동화와 간소화 기능이 많이 추가 되긴 했지만요..

그런데, 이말을 거꾸로 말해보자면, 사용자의 역량에 따라 tuning 할 수 있는 포인트가 많다는 이야기도 되죠.
또 이런 특성때문에 곳곳에 숨어 있는 고수들도 많이 있습니다.

아래의 SQL은 숨어 있는 이러한 기능들을 control 할 수 있는 parameter를 확인 할 수 있는 SQL 입니다.
물론 show parameter나 v$parameter에서 parameter의 값을 확인 할 수 있지만,
이 두개의 방법으로 찾을 수 있는 parameter는 일반 parameter와 변경된 hidden parameter만을 볼 수 있습니다.

아래의 SQL은 일반 parameter와 hidden parameter 모두 확인 가능한 parameter 입니다.

col value format a20
col description format a70
select a.inst_id "inst_id",  ksppinm "name",  ksppstvl "value",  ksppdesc "description"
from x$ksppi a,x$ksppsv b where a.indx = b.indx and ksppinm like '%&parameter%'
/

SQL만 덩그러니 post하긴 좀 그러니..
각 버전 별로 전체 parameter 갯수와 hidden parameter 개수를 비교해 봤습니다.

10g R2는 전체 1385개의 parameter 중 hidden parameter는 1127 개이고,
11g R1 은 1920개 중 1631개,
11g R2는 2399개 중 2057 개  입니다.
(제 VMware linux 서버 기준입니당)

버전이 높아 질수록 점점 숨겨지는 parameter도 늘어가네요. 
또 전체 parameter 중에서 감춰진 parameter가 대부분이군요..
약 70% 정도 되는 거 같네요.. 

요거 마스터 하면 고수가 될 수 있을 라나..




운영 중 spfile이 유실 되는 경우, 간편하게 recovery 할 수 있는 명령어가 oracle 11g에서 추가되었네요.

뭐 alert log file에 나온 parameter 정보나 show parameter 등으로도 만들 수 있지만 많이 귀찮죠.
(사실 spfile이나 init file 유실되는 건 본적은 없으나...)

create spfile from memory;
create spfile='/u01/oracle/app/oracle/product/11g/dbs/spfile_back.ora' from memory;







좋은 자료 하나 찾아 공유합니다.

GNU make 강좌

CONTENTS

1. make (만든다 ?)
    1.1 make 유틸리티
    1.2 make의 필요성

2. 간단한 Makefile
    2.1 Makefile 의 내부 구조
    2.2 Makefile 예제
    2.3 매크로의 사용
    2.4 레이블의 사용

3. 매크로(Macro) 와 확장자(Suffix) 규칙
    3.1 매크로란 무엇인가? (What is Macro)
    3.2 미리 정해져 있는 매크로 (Pre-defined macro)
    3.3 확장자 규칙 (Suffix rule)
    3.4 내부 매크로 (Internal macro)

4. Makefile를 작성할 때 알면 좋은 것들
    4.1 긴 명령어를 여러 라인으로 표시하기
    4.2 확장자 규칙의 이용 (Use suffix rule !!)
    4.3 매크로 치환 (Macro substitution)
    4.4 자동 의존 관계 생성 (Automatic dependency)
    4.5 다중 타겟 (Multiple target)
    4.6 순환 make (Recursive MAKE)
    4.7 불필요한 재컴파일 막기

5. make 중요 옵션 정리

6. Makefile 작성의 가이드라인

7. Makefile의 실제 예제
    7.1 프로그램 제작에 쓰일 수 있는 Makefile
    7.2 라이브러리와의 링크가 필요한 필요한 Makefile
    7.3 LaTeX에서 쓰일 수 있는 Makefile

8. make 수행 시에 나타나는 에러들

'Operation System' 카테고리의 다른 글

이것 저것 Unix 명령어들  (0) 2010.11.27
VMware 설정 관련 참고 POST들.  (1) 2010.01.12
Read hat Linux (in vmware) to Windows XP FTP setting  (0) 2009.12.31
Network 용어정리 2  (2) 2009.12.22
Network 용어정리 1  (0) 2009.12.22

대부분의 오라클 운영자는 '/as sysdba' 나 system 계정으로 작업을 합니다.
모니터링 중 특정 user에서 대해 수행되는 sql의 이상 등을 발견하는 경우 가끔 해당 sql을 직접 수행해 보는 경우가 있는데, v$sqltext 등에서 잡아온 sql을 그대로 수행하면 에러가 당연히 발생합니다.

해당 sql의 table list가 몇개 안될 경우 table 명 앞에 username을 지정하면, 수행은 가능하지만 귀찮기도 하고 어찌되었던 sql이 변경되 버리고 말죠.

또 다른 sql에서 권한이 있는 table을 수행할 경우에도 table의 각각의 username을 설정해야 합니다.
그게 아니라면 synonym을 따로 만들어 줘야 합니다.

이러한 경우 간단히 CURRENT_SCHEMA의 설정으로 이 모든 귀찮은 것을 해결할 수 있습니다.
CURRENT_SCHEMA는 현재 수행되는 SCHEMA환경을 지정한 SCHEMA로 변경해 줍니다.


SQL> CONNECT SCOTT/TIGER;
SQL> GRANT SELECT ON EMP TO JAMES;
SQL> CONNECT JAMES/TIGER;
SQL> SELECT COUNT(*) FROM SCOTT.EMP;
SQL> SELECT COUNT(*) FROM EMP;

SELECT COUNT(*) FROM EMP
                                       *
ERROR at line 1:
ORA-00942: table or view does not exist


위의 경우 당연히 에러가 발생하게 됩니다.
그러면 synonym이나 username을 추가 지정없이 수행하려면 다음의 CURRENT_SCHEMA를 SCOTT으로 지정해 줍니다.

SQL> CONNECT JAMES;
SQL> ALTER SESSION SET CURRENT_SCHEMA=SCOTT;
Session altered.

SQL> SELECT COUNT(*) FROM EMP;
COUNT(*)
10
...




'Oracle Database' 카테고리의 다른 글

Oracle Data Type  (0) 2009.12.18
Oracle 10g crs관련 명령들  (0) 2009.12.17
Oracle crs 설치 정보 확인  (0) 2009.12.11
Oracle Korea Magazin 2009년 겨울호 발간  (0) 2009.12.10
실례를 통해 알아본 Oracle Cluster의 활용  (0) 2009.11.25

Table partitioning은 Oracle의 대표적인 DW를 위한 기능이다.

이 기능은 테이블을 특정 partition set으로 나누어 관리 및 성능 상의 이점을 얻는다.
다음의 내용은 이러한 partition table의 종류와 간단한 정의이다.

Range Partitioning Method

column 값의 범위에 따라 partition을 나누는 가장 일반적인 방법이다. 이 방식은 대개 날짜와 같은 범위로 많이 나뉘게 되는데, AP의 성격에 따라 데이터가 특정 partition에 몰리는 경우 hash partition 방식이나, list partition 방식 등 다른 partition 방식을 통해 sub-partition을 나누기도 한다.


Create table test164874 (
ord_day         NUMBER(2),
ord_month       NUMBER(2),
ord_year        NUMBER(4),
ord_id  NUMBER(10)
)
storage (initial 12k next 12k pctincrease 0 minextents 1)
PARTITION BY RANGE (ord_year,ord_month,ord_day)
(
PARTITION P1 VALUES LESS THAN (2001,3,31) TABLESPACE PART1,
PARTITION P2 VALUES LESS THAN (2001,6,30) TABLESPACE part2,
PARTITION P3 VALUES LESS THAN (2001,9,30) TABLESPACE part3,
PARTITION P4 VALUES LESS THAN (2001,12,32) TABLESPACE part4
)
/


Hash Partitioning Method

partition key의 hash 값에 의해 partition으로 나눠진다. 일반적으로 균등한 분포를 가지며 성능상의 이유로 hash partition을 사용하기도 한다.


CREATE TABLE tabpart1(
ord_id   NUMBER(5),
ord_date DATE
)
PARTITION BY HASH(ord_id) PARTITIONS 16
STORE IN (tbs1,tbs2,tbs3,tbs4)
/


Composite Partitioning Method

Oracle 10g 이전엔 Range-List, Range-Hash composite partition 만 지원했으나, Oracle 11에서는 List-List, List-Hash, List-Range and Range-Range composite partition이 지원된다. 또 interval partition 방식에 대해서 Interval-Range, Interval-List and Interval-Hash가 가능하다.


   

CREATE TABLE TAB1(
     ord_id  NUMBER(10),
     ord_day    NUMBER(2),
     ord_month  NUMBER(2),
     ord_year   NUMBER(4)
     )
PARTITION BY RANGE (ord_year,ord_month,ord_day)
  SUBPARTITION BY HASH(ord_id) SUBPARTITIONS 8
  STORE IN (TBS1,TBS2,TBS3,TBS4,TBS5,TBS6,TBS7,TBS8)
     (  PARTITION P1 VALUES LESS THAN (2001,3,31),
        PARTITION P2 VALUES LESS THAN (2001,6,30),
        PARTITION P3 VALUES LESS THAN (2001,9,30),
        PARTITION P4 VALUES LESS THAN (2001,12,31)
 )
/


List Partitioning Method

Oracle 9i에 소개된 partition 방식으로 partition key의 값 자체에 의해 분리된 partition으로 데이터가 저장된다. 값에 의해 데이터가 partition 되므로 전혀 관계없는 데이터 값을 하나의 partition에 저장할 수 있다.

CREATE TABLE sales_list
(salesman_id NUMBER(5),
salesman_name VARCHAR2(30),
sales_state VARCHAR2(20),
sales_amount NUMBER(10),
sales_date DATE)
PARTITION BY LIST(sales_state)
(
PARTITION sales_west VALUES('California', 'Hawaii'),
PARTITION sales_east VALUES ('New York', 'Virginia', 'Florida'),
PARTITION sales_central VALUES('Texas', 'Illinois')
PARTITION sales_other VALUES(DEFAULT)
);

Interval Partitioning Method

Interval partition은 range partition 기능의 확장으로 개별 범위를 명시적으로 정의하지 않아도 해당 interval에 속하는 데이터가 입력 될 때 partition이 자동으로 생성된다.

CREATE TABLE interval_sales
( prod_id NUMBER(6)
, cust_id NUMBER
, time_id DATE
, channel_id CHAR(1)
, promo_id NUMBER(6)
, quantity_sold NUMBER(3)
, amount_sold NUMBER(10,2) )
PARTITION BY RANGE (time_id)
INTERVAL(numtodsinterval(7,'day'))
( PARTITION p0 VALUES LESS THAN (TO_DATE('1-1-2007', 'DD-MM-YYYY')) );

Reference Partitioning Method

Oracle 11g에서 소개된 partition 방식으로 “모-자” 관계의 table 간에 모 table의 partition key column의 복제 없이 모 table의 partition 구조를 따라가게 됩니다.

SQL> CREATE TABLE ref_part_parent
2 (pcol1 NUMBER PRIMARY KEY,
3 pcol2 VARCHAR2(10))
4 PARTITION BY RANGE (pcol1)
5 (PARTITION p1 VALUES LESS THAN (100),
6 PARTITION p2 VALUES LESS THAN (200),
7 PARTITION p3 VALUES LESS THAN (300),
8* PARTITION p4 VALUES LESS THAN (MAXVALUE))

Table created.

SQL> CREATE TABLE ref_part_child
2 (ccol1 NUMBER NOT NULL,
3 CONSTRAINT ccol1_fk FOREIGN KEY(ccol1) REFERENCES ref_part_parent(pcol1))
4 PARTITION BY REFERENCE(ccol1_fk);

Table created.

System Partitioning Method

oracle 11g에서 소개된 partition 방식으로 다른 partition 방식과의 가장 큰 차이는 partition key를 정의하지 않는데 있다. 즉, system이 알아서 partition을 해준다.

CREATE TABLE systab (c1 integer, c2 integer)
PARTITION BY SYSTEM
(
PARTITION p1 TABLESPACE tbs_1,
PARTITION p2 TABLESPACE tbs_2,
PARTITION p3 TABLESPACE tbs_3,
PARTITION p4 TABLESPACE tbs_4
); 

Virtual column-based Partitioning Method

virtual column partition 방식은 partition key의 값이 물리적으로 존재하지 않은 경우에도 virtual column 값에 의해 partition을 할 수 있게 한다.

 CREATE TABLE employees
  (employee_id  number(6) not null, first_name varchar2(30), 
   last_name varchar2(40) not null, email varchar2(25),
   phone_number varchar2(20), hire_date  date not null,
   job_id  varchar2(10) not null, salary number(8,2),
   commission_pct number(2,2), manager_id  number(6),
   department_id number(4),
   total_compensation as (salary *( 1+commission_pct))
   )
    PARTITION BY RANGE (total_compensation)
     (
       PARTITION p1 VALUES LESS THAN (50000),
       PARTITION p2 VALUES LESS THAN (100000),
       PARTITION p3 VALUES LESS THAN (150000),
       PARTITION p4 VALUES LESS THAN (MAXVALUE)
     );






오라클은 DB link와 synonym을 통해서 remote oracle database에 있는 table을 local database 서버에 있는 것처럼 query가 가능합니다. 하지만 내부적으로는 remote database로 관련 query를 수행해 return 되는 데이터를 이용해 결과 값을 출력해줍니다. (당연하죠..ㅎㅎ) 그러나 remote database의 table에 대한 정보가 없기 때문에 일반적인 role을 이용해 query를 생성, 수행 요청하게 됩니다.

National Hurricane Center
(아무 상관없는 그림이지만 내용이 작아 붙여 봅니다. ^^;)


아래 box 안의 role은 remote database로 query를 수행하는 일반적인 규칙입니다. 참조한 문서가 오래전꺼긴 한데, 큰 차이는 없으리라.. 생각되는 군요.

간단히 보자면 ..

MAX() 같은 group 함수는 전달 되지 않으니, 테이블의 범위에 따라서는 엄청난 데이터가 local로 전송된 후 MAX() 값 등을 구할 수도 있겠군요.

또 상수 조건이 있는 table은 remote로 해당 조건이 전달 되겠지만, 그렇지 않은 경우는 FULL TABLE SCAN을 할 수 도 있겠고요..

ORDER BY도 local에서 수행된다니, 대상이 많으면 이것도 성능에 영향을 줄 수 있겠네요.

  1. Aggregate functions like MAX(), COUNT() are NOT passed across the net but rather are performed on the local node.
  2. Expressions in the SELECT list are decomposed into columns and evaluated when the data is retrieved.
  3. Only a relevant subset of columns are fetched across the net.
  4. An expression in a WHERE clause is passed across to the remote database if it compares the remote column to a literal (eg ename = 'KING').
  5. Expressions in a WHERE clause are passed to the remote database if all columns are in the expression are located in the same remote table the remote database (eg emp.sal * 0.20 > emp.bonus)
  6. Datatype conversion functions like TO_CHAR() in a WHERE clause are subject to the conditions in #4 and #5.
  7. The optimizer only has knowledge of local indexes when making decisions about how to execute a query.
  8. Remote indexes can be still be used to resolve the decomposed query sent to the remote database.
  9. GROUP BY is not sent to the remote database.
  10. ORDER BY is not sent to the remote database.

이 내용은 oracle metalink "Note 1004553.6 DISTRIBUTED QUERY ANALYSIS"를 참조했습니다.

써놓고 보니 DB link를 이용하지 말라는 이야기가 된 것 같아 몇줄 더 씁니다.

물론 group 함수, order by 등의 처리가 local database에서 처리가 되지만 이러한 것들을 피해가는 방법들은 다 있기 마련이죠. view를 만들어 remote에서 group 함수 처리를 한다든지, join의 경우 아예 한 곳에서 처리하게 한다든지, temporary table을 만들어 처리하거나.. 뭐 이런

요는 network을 통한 전달되는 데이터의 양을 얼마나 많이 줄이느냐 겠죠.

위의 metalink note 보시면 몇몇 예제가 있으니 참조하세요.







SQL> alter table p_emp rename partition emp_p1 to emp_p01;
SQL> alter table p_emp rename partition emp_p2 to emp_p02;
SQL> alter table p_emp rename partition emp_p3 to emp_p03;

SQL> select table_name,partition_name,high_value from dba_tab_partitions where table_name = 'P_EMP';

TABLE_NAME                     PARTITION_NAME                 HIGH_VALUE
------------------------------ ------------------------------ ----------
P_EMP                          EMP_MAX                        MAXVALUE
P_EMP                          EMP_P01                        2000
P_EMP                          EMP_P02                        3000
P_EMP                          EMP_P03                        4000

partition table의 partition 이름 변경시 index의 partition 이름은 같이 변경되지 않는다. 따라서 index partition이름도 같이 변경해 주어야 한다.

SQL>  select INDEX_NAME,PARTITION_NAME,HIGH_VALUE,STATUS from dba_ind_partitions where index_name = 'P_EMP_I';

INDEX_NAME           PARTITION_NAME                 HIGH_VALUE STATUS
-------------------- ------------------------------ ---------- --------
P_EMP_I              EMP_MAX                        MAXVALUE   USABLE
P_EMP_I              EMP_P1                         2000       USABLE
P_EMP_I              EMP_P2                         3000       USABLE
P_EMP_I              EMP_P3                         4000       USABLE

SQL> ALTER INDEX p_emp_i RENAME PARTITION emp_p1 TO emp_p01;
SQL> ALTER INDEX p_emp_i RENAME PARTITION emp_p2 TO emp_p02;
SQL> ALTER INDEX p_emp_i RENAME PARTITION emp_p3 TO emp_p03;

SQL>  select INDEX_NAME,PARTITION_NAME,HIGH_VALUE,STATUS from dba_ind_partitions where index_name = 'P_EMP_I';

INDEX_NAME           PARTITION_NAME                 HIGH_VALUE STATUS
-------------------- ------------------------------ ---------- --------
P_EMP_I              EMP_MAX                        MAXVALUE   USABLE
P_EMP_I              EMP_P01                        2000       USABLE
P_EMP_I              EMP_P02                        3000       USABLE
P_EMP_I              EMP_P03                        4000       USABLE










1. partition table & local index 생성.

CREATE TABLE p_emp (sal NUMBER(7,2))
 PARTITION BY RANGE(sal)
 (partition emp_p1 VALUES LESS THAN (2000),
  partition emp_p2 VALUES LESS THAN (4000),
  partition emp_max VALUES LESS THAN (MAXVALUE));

 create index p_emp_i on p_emp (sal) local;

insert into p_emp values (1000);
insert into p_emp values (2000);
insert into p_emp values (3000);
commit;

SQL> select table_name,partition_name,high_value from dba_tab_partitions where table_name = 'P_EMP';

TABLE_NAME                     PARTITION_NAME                 HIGH_VALUE
------------------------------ ------------------------------ ----------
P_EMP                          EMP_MAX                        MAXVALUE
P_EMP                          EMP_P1                         2000
P_EMP                          EMP_P2                         4000

SQL> select INDEX_NAME,PARTITION_NAME,HIGH_VALUE,STATUS from dba_ind_partitions  where index_name = 'P_EMP_I';

INDEX_NAME           PARTITION_NAME                 HIGH_VALUE STATUS
-------------------- ------------------------------ ---------- --------
P_EMP_I              EMP_MAX                        MAXVALUE   USABLE
P_EMP_I              EMP_P1                         2000       USABLE
P_EMP_I              EMP_P2                         4000       USABLE

2. split partition table

전체 partition range의 중간에 partition을 삽입히기 위해서는 split partition 명령을 사용해야 한다. MAXVALUE가 없는 상태에서 제일 끝에 추가할 경우는 add partition 명령을 사용한다.

SQL> alter table p_emp split partition emp_p2 at (3000) into (partition emp_p2, partition emp_p3);

SQL> select table_name,partition_name,high_value from dba_tab_partitions where table_name = 'P_EMP';

TABLE_NAME                     PARTITION_NAME                 HIGH_VALUE
------------------------------ ------------------------------ ----------
P_EMP                          EMP_MAX                        MAXVALUE
P_EMP                          EMP_P1                         2000
P_EMP                          EMP_P2                         3000
P_EMP                          EMP_P3                         4000


SQL> select INDEX_NAME,PARTITION_NAME,HIGH_VALUE,STATUS from dba_ind_partitions  where index_name = 'P_EMP_I';

INDEX_NAME           PARTITION_NAME                 HIGH_VALUE STATUS
-------------------- ------------------------------ ---------- --------
P_EMP_I              EMP_MAX                        MAXVALUE   USABLE
P_EMP_I              EMP_P1                         2000       USABLE
P_EMP_I              EMP_P2                         3000       UNUSABLE
P_EMP_I              EMP_P3                         4000       UNUSABLE

partition table의 local partition index도 같이 split 되나 데이터가 있는 상태라면 "UNUSABLE" 상태로 되므로 이에 대한 rebuild 작업이 반드시 필요하다.

If the partition you are splitting contains data, the ALTER TABLE...SPLIT PARTITION statement marks UNUSABLE the new partitions (there are two) in each local index, all global index partitions, and any
global nonpartitioned index. You must rebuild such affected indexes or index partitions.

(Metalink Note 165599.1 Top Partitioned Tables Issues 중.)


SQL> alter index p_emp_i rebuild partition emp_p2;
SQL> alter index p_emp_i rebuild partition emp_p3;

SQL> select INDEX_NAME,PARTITION_NAME,HIGH_VALUE,STATUS from dba_ind_partitions where index_name = 'P_EMP_I';

INDEX_NAME           PARTITION_NAME                 HIGH_VALUE STATUS
-------------------- ------------------------------ ---------- --------
P_EMP_I              EMP_MAX                        MAXVALUE   USABLE
P_EMP_I              EMP_P1                         2000       USABLE
P_EMP_I              EMP_P2                         3000       USABLE
P_EMP_I              EMP_P3                         4000       USABLE






CASE 문은 PL/SQL 없이 SQL문 안에서 if-then-else logic을 구현하는 데 사용합니다.

CASE 문은 "Simple case expressions" 와 "Searched case expressions"로 나눌 수 있는데, "Simple case expressions"은 expression을, "Searched case expressions"은 condition을 사용해 return 값이 결정된다.

다음은 simple CASE 구문의 사용방법이다.

CASE search_expression
  WHEN expression1 THEN result1
  WHEN expression2 THEN result2
  ...
  WHEN expressionN THEN resultN
  ELSE default_result
END

위의 예제는 search_expression이 expression1,2,3.. 일 경우 result1,2,3.. 이 출력된다.

SELECT product_id, product_type_id,
  CASE product_type_id
  WHEN 1 THEN 'Book'
  WHEN 2 THEN 'Video'
  WHEN 3 THEN 'DVD'
  WHEN 4 THEN 'CD'
  ELSE 'Magazine'
  END
FROM products;

PRODUCT_ID PRODUCT_TYPE_ID CASEPROD
---------- --------------- --------
         1               1 Book
         2               1 Book
         3               2 Video
         4               2 Video
         5               2 Video
         6               2 Video
         7               3 DVD
         8               3 DVD
         9               4 CD
        10               4 CD
        11               4 CD
        12                 Magazine

다음은 searched CASE 구문의 사용방법이다.

CASE
  WHEN condition1 THEN result1
  WHEN condition2 THEN result2
  ...
  WHEN conditionN THEN resultN
  ELSE default_result
END

위의 예는 condition1,2 가 true 일 경우 result1,2,.. 출력한다.

SELECT product_id, product_type_id,
  CASE
  WHEN product_type_id = 1 THEN 'Book'
  WHEN product_type_id = 2 THEN 'Video'
  WHEN product_type_id = 3 THEN 'DVD'
  WHEN product_type_id = 4 THEN 'CD'
  ELSE 'Magazine'
  END
FROM products;

PRODUCT_ID PRODUCT_TYPE_ID CASEPROD
---------- --------------- --------
         1               1 Book
         2               1 Book
         3               2 Video
         4               2 Video
         5               2 Video
         6               2 Video
         7               3 DVD
         8               3 DVD
         9               4 CD
        10               4 CD
        11               4 CD
        12                 Magazine

SELECT product_id, price,
  CASE
  WHEN price > 15 THEN 'Expensive'
  ELSE 'Cheap'
  END
FROM products;

PRODUCT_ID      PRICE CASEWHENP
---------- ---------- ---------
         1      19.95 Expensive
         2         30 Expensive
         3      25.99 Expensive
         4      13.95 Cheap
         5      49.99 Expensive
         6      14.95 Cheap
         7      13.49 Cheap
         8      12.99 Cheap
         9      10.99 Cheap
        10      15.99 Expensive
        11      14.99 Cheap
        12      13.49 Cheap






BFT (BigFileTablespace)는 oracle 10g에서 사용가능한 tablespace type 이다. Bigfile Tablespace는 하나의 매우 큰 datafile을 갖는 tablespace를 말한다. Bigfile tablespace의 개념이 만들어 지면서 기존의 일반적인 tablespace는 자동으로 smallfile tablespace로 불린다.

SMALLFILE tablespace와 BIGFILE tablespace는 database내에 공존할 수 있다.

      SQL> select TABLESPACE_NAME, BIGFILE from DBA_TABLESPACES;

      TABLESPACE_NAME                BIG
      ------------------------------ ---
      SYSTEM                         NO
      UNDOTBS1                       NO
      SYSAUX                         NO
      TEMP                           NO
      USERS                          NO
      TEST_BIG                       YES

BIGFILE tablespace는 하나의 datafile만을 사용하게 된다. 이는 datafile에 대한 관리가 간편해 질 수 있다는 것을 의미하며, 일반적인 SMALLFILE tablespace에서 사용하던 다음과 같은 option도 역시 사용가능하다.

      SQL> ALTER TABLESPACE test_big AUTOEXTEND OFF;
      Tablespace altered.

      SQL>  ALTER TABLESPACE test_big AUTOEXTEND ON;
      Tablespace altered.

      SQL> ALTER TABLESPACE test_big RESIZE 2M;
      Tablespace altered.

BIGFILE tablespace는 다음과 같이 사용될 수 있다.

      --> ASM (Automatic Storage Management)
      --> a logical volume manager supporting striping/RAID
      --> dynamically extensible logical volumes
      --> Oracle Managed Files (OMF)

만약 default로 BIGFILE tablespace를 생성하고 싶다면 다음과 같이 tablespace 생성 option을 바꿀 수 있다.

    SQL> select * from database_properties
          where property_name='DEFAULT_TBS_TYPE';

     PROPERTY_NAME        PROPERTY_VALUE  DESCRIPTION
     -------------------- --------------- ------------------------
     DEFAULT_TBS_TYPE     SMALLFILE       Default tablespace type
   
     SQL> ALTER DATABASE SET DEFAULT bigfile TABLESPACE;
     Database altered.

     SQL> CREATE TABLESPACE big_test2
          DATAFILE '/ORACLE10/ORCL/testbig2.dbf' size 1M;

     Tablespace created.

     SQL> select TABLESPACE_NAME, BIGFILE from DBA_TABLESPACES;

     TABLESPACE_NAME                BIG
     ------------------------------ ---------
     ...
     USERS                          NO
     TEST_BIG                       YES
     TEST_BIG2                      YES

앞서 말한 것 처럼 BIGFILE tablespace에는 datafile 추가는 불가능하다.

      SQL> ALTER TABLESPACE test_big
           ADD DATAFILE '/ORACLE10/ORCL/testbig2.dbf' size 500G;

      ALTER TABLESPACE test_big
      *
      ERROR at line 1:
      ORA-32771: cannot add file to bigfile tablespace


여러 datafile을 사용해 큰 공간을 확보하는 방법에 비해 하나의 큰 파일로 tablespace를 구성하는 이 방법은 관리상의 이점이 있으나, backup이나 recovery 단계에서는 큰 file에 대한 backup과 file 손상이 발생할 경우 전체를 restore해야 하기 때문에 오히려 부담이 될 수 도 있다. 따라서 각각의 tablespace type에 대한 이점과 단점을 구분하고 적용해야할 것이다.

참고 문서 :
Note 262472.1  10g: BIGFILE Type Tablespaces Versus SMALLFILE Type
Note 243245.1  10G New Storage Features and Enhancements
Note 1057891.6 HOW TO USE DBMS_ROWID PROCEDURE AND FUNCTIONS








일반적으로 IN operation은 특정 table(view) data의 row 값에 따른 다른 table의 데이터를 추출해내고자 할 때 자주 사용되는데, 가끔 IN operation을 row가 있는지 check하는 용도로 사용하기도 한다. 그러나 row가 존재하는지에 대해서는 EXISTS라는 근사한 operation을 따로 제공하고 있다. 

주의해야 할 점은 EXISTS와 IN은 다른 점이 존재하므로 이에 대해 유의해야 한다.  EXISTS는 단지 해당 row가 존재하는지만 check하고 더이상 수행되지 않으나 IN은 실제 존재하는 데이터들의 모든 값까지 확인한다. 따라서 일반적으로 EXISTS operation이 더 좋은 성능을 보이므로 가능하면 EXISTS를 사용하는 것이 바람직해 보인다.

또한가지 EXISTS와 IN 사용시 주의해야 할 점은 join 되는 column에 NULL을 갖는 row가 존재한다면, NOT EXISTS는 true값을, NOT IN은 false 가 return 된다. 즉, NOT IN을 사용하면 조건에 맞는 데이터가 있다고 하더라도 NULL이 존재하면 "no rows selected"라고 나오게 된다. 따라서 NVL을 이용한 NULL 처리가 꼭 필요하다.

다음은 NOT EXISTS operation을 이용한 방법이다.
예제의 products table의 product_type_id column 데이터 중 일부가 NULL로 입력되어 있다.

SELECT product_type_id, name
FROM product_types outer
WHERE NOT EXISTS
  (SELECT 1
   FROM products inner
   WHERE inner.product_type_id = outer.product_type_id);

PRODUCT_TYPE_ID NAME
--------------- ----------
              5 Magazine

다음은 동일한 데이터에 대해 NOT IN을 사용했을 경우다. NULL data에 의해 조건 자체가 false가 되어 "no rows selected"라는 결과가 발생한다.

SELECT product_type_id, name
FROM product_types
WHERE product_type_id NOT IN
  (SELECT product_type_id
   FROM products);

no rows selected

다음은 NVL()을 이용해 NULL값을 처리한 후의 결과이다.

SELECT product_type_id, name
FROM product_types
WHERE product_type_id NOT IN
  (SELECT NVL(product_type_id, 0)
   FROM products);

PRODUCT_TYPE_ID NAME
--------------- ----------
              5 Magazine

NOT IN operation의 경우 위와 같은 사실을 미리 인지하고 있지 않다면 나중에 이러한 경우를 찾기는 매우 어려울 수 있다. 따라서 NULL에 대한 operation이나 table의 default column 값등의 지정 등의 세심한 주의가 필요하다.



* 여기저기서 좋다는 책 몇권 추천합니다. 고수가 되는 그날까지.. 파이팅!!



오라클의 SQL 언어를 수행할 수 있는 tool인 sqlplus에서는 변수를 지원한다.

변수는 다들 잘 알고 있듯이 특정 변경되는 값을 변수값으로 입력 받아 이를 해당 변수와 치환해주게 된다. SQLPLUS에서 지원하는 변수는 2가지로 변수값이 지속되지 않는 변수 temporary variable과 그 변수 값이 지속되어 해당 값을 삭제, 재정의 또는 sqlplus를 빠져나갈때 까지 유지하는 defined variable이 있다.

Temporary variable의 경우 SQL구문의 수행 시 해당 변수값을 입력 받아 사용되며 동일한 SQL이 재수행 되더라도 해당 변수값을 다시 묻게 된다.

SQL> SELECT product_id, name, price
  2  FROM products
  3  WHERE product_id = &product_id_var;

Enter value for product_id_var: 2
old   3: WHERE product_id = &product_id_var
new   3: WHERE product_id = 2

PRODUCT_ID NAME                                PRICE
---------- ------------------------------ ----------
         2 Chemistry                              30

SQL> /
Enter value for product_id_var: 3
old   3: WHERE product_id = &product_id_var
new   3: WHERE product_id = 3

PRODUCT_ID NAME                                PRICE
---------- ------------------------------ ----------
         3 Supernova                           25.99

위의 예를 보면 product_id_var 변수의 값이 3으로 치환되고 이에 대한 결과를 보여준다. 이러한 old/ new 값에 대한 output은 VERIFY option을 이용해 출력을 제어할 수 있다.

SQL> SET VERIFY OFF
SQL> /

Enter value for product_id_var: 4

PRODUCT_ID NAME                                PRICE
---------- ------------------------------ ----------
         4 Tank War                            13.95

다시 변수에 대한 old/ new value를 출력하려면 VERIFY option을 on으로 설정한다.

SQL> SET VERIFY ON

또 "SET DEFINE" 명령을 이용해 변수 앞의 ampersand (&)도 바꿔 줄 수 있다. UNIX 상에서 해당 character가 다른 의미로 사용되고 있는 경우를 제외하면 별로 사용할 일은 없을 듯 하지만..

SQL> SET DEFINE '#'
SQL> SELECT product_id, name, price
  2  FROM products
  3  WHERE product_id = #product_id_var;

Enter value for product_id_var: 5
old   3: WHERE product_id = #product_id_var
new   3: WHERE product_id = 5

PRODUCT_ID NAME                                PRICE
---------- ------------------------------ ----------
         5 Z Files                             49.99

다시 원래의 ampersand (&)로 바꾸려면 다음과 같이 수행해 준다.

SQL> SET DEFINE '&'

가끔 동일한 변수를 같은 SQL문에서 사용하게 되는데 이때 동일한 변수라도 사용한 개수만큼 다시 값을 묻게 된다. 이러한 현상을 막기 위해서는 ampersand를 두개로 지정해 준다.  (&&)

SQL> SELECT name, &col_var
  2  FROM &table_var
  3  WHERE &col_var = &col_val;

Enter value for col_var: product_type_id
old   1: SELECT name, &col_var
new   1: SELECT name, product_type_id

Enter value for table_var: products
old   2: FROM &table_var
new   2: FROM products

Enter value for col_var: product_type_id
Enter value for col_val: 1
old   3: WHERE &col_var = &col_val
new   3: WHERE product_type_id = 1

NAME                           PRODUCT_TYPE_ID
------------------------------ ---------------
Modern Science                               1
Chemistry                                    1

You can avoid having to repeatedly enter a variable by using &&. For example:

SELECT name, &&col_var
FROM &table_name
WHERE &&col_var = &col_val;


Defined Variable은 선언된 변수를 여러번 사용이 가능하다. 이 값은 재정의 되거나, 변수값이 삭제되거나, SQLPLUS를 빠져나가기 전까지 사용가능하다. Defined variable은 "DEFINE" 명령을 통해 변수값이 설정, 조회하며 "UNDEFINE"명령에 의해 변수값이 삭제된다. 또 "ACCEPT" 명령을 통해 해당 변수값을 유저로 부터 받아들일 수 있다.

SQL> DEFINE product_id_var = 7
SQL> DEFINE product_id_var

DEFINE PRODUCT_ID_VAR          = "7" (CHAR)

SQL> SELECT product_id, name, price
      2  FROM products
      3  WHERE product_id = &product_id_var;

old   3: WHERE product_id = &product_id_var
new   3: WHERE product_id = 7

ACCEPT 명령은 해당 변수의 type과 입력 받을 format, prompt 형태 등의 다양한 지정이 가능하다. HIDE option의 경우 9i 이전엔 asterisk characters (*)로 보여주지만 10g 부터는 아무런 문자를 출력하지 않는다.

ACCEPT variable_name [type] [FORMAT format] [PROMPT prompt] [HIDE]

SQL> ACCEPT customer_id_var NUMBER FORMAT 99 PROMPT 'Customer id: '
Customer id: 5

SQL> ACCEPT date_var DATE FORMAT 'DD-MON-YYYY' PROMPT 'Date: '
Date: 12-DEC-2006

SQL> ACCEPT password_var CHAR PROMPT 'Password: ' HIDE
Password: *******

현재 설정되어 있는 변수값을 clear 하기 위해서는 UNDEFINE 명령이 사용된다. 물론 재정의나 SQLPLUS를 logout 하면 해당 값은 clear 되지만 다른 script를 계속 수행한다면 예상치 못한 상황을 만나지 않기 위해 깨끗이 정리할 필요가 있다.

SQL> UNDEFINE customer_id_var
SQL> UNDEFINE date_var
SQL> UNDEFINE password_var





Oracle AWR 데이터는 정해진 interval 마다 oracle statistic 값을 retention 기간만큼 보관하게 됩니다.
따라서 해당 시점에 발생된 statistic 값을 보려면 관련 table에 대해 self join을 해야하는데,
이때 편하게 쓸 수 있는 oracle 함수가 LAG 합수 입니다.

LAG is an analytic function. It provides access to more than one row of a table at the same time without a self join. Given a series of rows returned from a query and a position of the cursor, LAG provides access to a row at a given physical offset prior to that position.

If you do not specify offset, then its default is 1. The optional default value is returned if the offset goes beyond the scope of the window. If you do not specify default, then its default is null.

You cannot nest analytic functions by using LAG or any other analytic function for value_expr. However, you can use other built-in function expressions for value_expr.

[참고 ] Oracle 8.1.7 SQL reference [ LAG 함수 ]


간단히 예를 들면..
다음 처럼 DB_TIME 값의 변경 내역을 알고 싶다면 동일한 table에 대한 self join이 필요한데,
이 lag over 함수를 사용하면 join이 필요없어 집니다.

select a.snap_id,a.stat_name,a.value, b.value , a.value - b.value
from
DBA_HIST_SYS_TIME_MODEL a,
DBA_HIST_SYS_TIME_MODEL b
where a.snap_id = b.snap_id + 1
and a.stat_id = 3649082374
and a.stat_id = b.stat_id
/

select snap_id,stat_name,value, lag(value) over (order by snap_id),
       value - nvl(lag(value) over (order by snap_id),0)
from DBA_HIST_SYS_TIME_MODEL
where stat_id = 3649082374
/






오라클에서 수행되는 cursor의 수행 정보와 이와 관련된 각종 statistic 정보를 확인할 수 있는 view가 몇개 있습니다.
다음은 해당 view에 대한 비교와 column 정보들, 그리고 해당 view를 이용한 몇개의 sql script 들입니다.


V$SQL_PLAN_STATISTICS:
각 operation에 대한 execution statistics 정보를 제공한다.

1)EXECUTIONS:
Child cursor의 수행된 횟수 이다. 따라서 동일한 SQL이더라도 optimizer 환경이나 bind variable size 등의 변경에 의해 다른 child cursor를 가질 수 있으므로 이에 대한 고려도 필요하다.
두개의 세션에서 동일한 SQL을 2회 수행하는 경우나, 같은 세션에서 동일한 SQL을 2회 수행한 경우 동일하게 2의 값을 갖는다.

2)LAST_OUTPUT_ROWS and OUTPUT_ROWS:
LAST_OUTPUT_ROWS는 해당 operation에 의해 마지막에 처리된 실제 row 수 이며, OUTPUT_ROWS는 누적 합이다.

3)LAST_DISK_READS and DISK_READS:
LAST_DISK_READS는 해당 operation이 disk를 읽은 횟수를 의미하며, DISK_READS는 누적 합이다.

V$SQL_PLAN_STATISTICS_ALL:

다음의 관련 view의 데이터에 대한 전체적인 정보를 갖는다.
V$SQL_PLAN                   (all operations, objects, cost, cardinality etc)
V$SQL_PLAN_STATISTICS (execution statistics as above)
V$SQL_WORKAREA           (memory usage)

1) estimated_optimal_size
해당 operation을 메모리상에서 처리하기 위해 측정된 memory size (KB)

2) last_memory_used
cursor의 마지막 execution 동안 사용된 memory (KB)

3) active_time
Average active time (in centi-seconds)

다음의 SQL script는 특정 SQL cursor에 대한 plan과 관련 statistic 정보를 보여줍니다.

qeps.sql과 qep.sql을 생성해 수행하면 SQL의 성능을 평가하는 8개의 항목에 대해 지정된 갯수의 SQL과 그에 따른 statistic 정보를 보여줍니다. init parameter인 statistics_level를 ALL로 설정해야 정상적인 결과를 보여줍니다.

참고 :
Note 186548.1 9i Release 2 Cached cursors information in the row source level
Note 260942.1 Display Execution plans from Statement's in V$SQL_PLAN
Note 550578.1 How to Obtain the most Resource Intensive SQL Execution Plans using the Libr...





AWR table map을 찾던 중 "A Tour of the AWR Tables"라는 NOCOUG Summer Conference에서 소개된 자료를 확인할 수 있었습니다. 제목을 보니 AWR관련 table에 대한 여러 힌트를 얻을 수 있을 듯해서 자료를 보니 "load spike"를 찾기 위한 좀 다른 방법을 설명하고 있네요.

이전 " oracle awr 설정 시 고려해야 할 점" post에서 강호동, 이건희 회장까지 등장시키며 AWR 자료 수집 주기를 15 ~20분으로 줄여야한다고 글을 썼는데, 이 글의 저자는 "In my experience, the hourly interval is appropriate." 라고 하더군요. 저자는 DBA_HIST_SYSSTAT의 DB time, elapsed time 등의 load profile 자료를 사용하지 않고 1초마다 수집되는 ASH의 자료를 이용해 "load spike"를 찾는 방법을 제시하고 있습니다.

오옷 .. 그런 방법이.. 근데, 그 외의 성능관련 정보는 어떻게... --;
추가적인 AWR 관련 table을 이용한 문제가 될만한 SQL 찾는 방법 등도 같이 소개합니다.

Average Active Session이 튀는 시간 찾기.
column sample_hour format a16

select
   to_char(round(sub1.sample_time, 'HH24'), 'YYYY-MM-DD HH24:MI') as sample_hour,
   round(avg(sub1.on_cpu),1) as cpu_avg,
   round(avg(sub1.waiting),1) as wait_avg,
   round(avg(sub1.active_sessions),1) as act_avg,
   round( (variance(sub1.active_sessions)/avg(sub1.active_sessions)),1) as act_var_mean
from
   ( -- sub1: one row per second, the resolution of SAMPLE_TIME
     select
        sample_id,
        sample_time,
        sum(decode(session_state, 'ON CPU', 1, 0))  as on_cpu,
        sum(decode(session_state, 'WAITING', 1, 0)) as waiting,
        count(*) as active_sessions
     from
        dba_hist_active_sess_history
     where
        sample_time > sysdate - (&hours/24)
     group by
        sample_id,
        sample_time
   ) sub1
group by
   round(sub1.sample_time, 'HH24')
order by
   round(sub1.sample_time, 'HH24')
;

SAMPLE_HOUR          CPU_AVG   WAIT_AVG    ACT_AVG ACT_VAR_MEAN
----------------- ---------- ---------- ---------- ------------
2008-04-16 07:00         1.4         .4        1.8           .6
2008-04-16 08:00         1.8         .5        2.3            1
2008-04-16 09:00         2.3         .5        2.8          1.3
2008-04-16 10:00         2.6         .6        3.2          2.3
2008-04-16 11:00         3.5         .6        4.1          2.3
2008-04-16 12:00         2.4         .6          3          1.1
2008-04-16 13:00         2.3         .6        2.9            1
2008-04-16 14:00         3.7        2.7        6.4         95.4   <== spike in variance
2008-04-16 15:00         3.1         .7        3.8          1.9
2008-04-16 16:00         2.9         .7        3.6          1.6
2008-04-16 17:00         2.3         .4        2.7           .9
2008-04-16 18:00         2.1         .6        2.7          2.6

Average Active Session이 튀는 시간대의 특정 분단위 찾기.
column sample_minute format a16

select
   to_char(round(sub1.sample_time, 'MI'), 'YYYY-MM-DD HH24:MI') as sample_minute,
   round(avg(sub1.on_cpu),1) as cpu_avg,
   round(avg(sub1.waiting),1) as wait_avg,
   round(avg(sub1.active_sessions),1) as act_avg,
   round( (variance(sub1.active_sessions)/avg(sub1.active_sessions)),1) as act_var_mean
from
   ( -- sub1: one row per second, the resolution of SAMPLE_TIME
     select
        sample_id,
        sample_time,
        sum(decode(session_state, 'ON CPU', 1, 0))  as on_cpu,
        sum(decode(session_state, 'WAITING', 1, 0)) as waiting,
        count(*) as active_sessions
     from
        v$active_session_history
     where
        sample_time > sysdate - (&minutes/1440)
     group by
        sample_id,
        sample_time
   ) sub1
group by
   round(sub1.sample_time, 'MI')
order by
   round(sub1.sample_time, 'MI')
;

SAMPLE_MINUTE           CPU_AVG   WAIT_AVG    ACT_AVG ACT_VAR_MEAN
-------------------- ---------- ---------- ---------- ------------
2008-04-16 13:54:00           3          1          4            0
2008-04-16 13:55:00         3.2         .3        3.5           .7
2008-04-16 13:56:00         4.2         .3        4.5          3.4
2008-04-16 13:57:00         3.8         .8        4.7           .7
2008-04-16 13:58:00         6.3          1        7.3          1.6
2008-04-16 13:59:00         3.4         .4        3.8           .2
2008-04-16 14:00:00         8.3         .5        8.8          1.8
2008-04-16 14:01:00        10.7        2.2       12.8           .5
2008-04-16 14:02:00         3.5         .7        4.2           .5
2008-04-16 14:03:00         2.6        1.2        3.8          1.5
2008-04-16 14:04:00         3.3        1.2        4.5          1.3
2008-04-16 14:05:00         8.2         .7        8.8          2.1
2008-04-16 14:06:00         6.7        1.3          8          1.1
2008-04-16 14:07:00         4.7        3.2        7.8          3.7
2008-04-16 14:08:00        20.5      109.8      130.3          170  <== spike in AAS
2008-04-16 14:09:00           6        1.3        7.3         10.3
2008-04-16 14:10:00         2.6         .4          3           .8
2008-04-16 14:11:00           4         .3        4.3          1.1
2008-04-16 14:12:00         5.7         .8        6.5          1.6
2008-04-16 14:13:00           3         .3        3.3           .7
2008-04-16 14:14:00         1.8         .7        2.5           .6
2008-04-16 14:15:00         3.3          2        5.3          2.2


 

+ Recent posts