3) IOT (index organizaion table) 테이블 구성
   - table random 엑세스가 발생하지 않도록 테이블을 아예 인덱스 구조로 생성한 object 

    ⑴ IOT 의 장점 
       - 인위적으로 클러스터링 팩터를 좋게 만드는 방법중에 하나여서 Logical read를 줄일 수 있다. 
       - 기존에는 인덱스 + 테이블이였다면, lOT는 인덱스만 만들면 되므로, 저장 공간이 절약된다. 

    ⑵ IOT의 단점 
        - 데이터 입력할 때, 성능이 느리다. 
   
    ⑶ IOT 생성 및 데스트 
        ① create table emp_iot
           (empno, ename, job, mgr, hiredate, sal, comm, deptno, constraint pk_emp_iot primary key(empno) )
           organization index
            as
                 select * from emp  ;

              * IOT 생성시 pirmary key 가 없으면 테이블이 생성되지 않는다. 
              * 기존 테이블에 primary key가 걸려 있어도 의미가 없다. 새로 생기는 table에 primary key를 만들어 주어야 한다.
                  (ctas 사용시 not null 제약을 제외한 나머지 제약은 따라오지 않는다.) 

        ② select * from emp_iot ;
             -- consistent gets 5 
             -- index fast full scan
 
     ⑷ IOT 저장 영역 
         ① PK 속성 영역 : 자주 조회 조건에서 검색되는 컬럼들이 저장된 저장 영역

         ② 오버 플로우 영역 : 값은 필요해서 저장해두지만 출력이나 조회조건으로 거의 사용되지 않는 컬럼들을 저정하는 저장 영역
         
         * 영역을 나누어서 사용하는 이유는 검색 속도를 좀 더 높이기 위해서 
         * IOT는 table이 아니라 index로 저장 된다. 검색시에는 object_type 이나 segment_type을 index로 하여야 찾을 수 있다. 
         * 그러나 drop 이나 truncate 명령어를 사용할 때에는 table 옵션을 사용한다. 
 

  4) 클러스터 테이블 

     ⑴ 클러스터 테이블이란 
        - 클러스터 키 값이 같은 레코드가 한 블럭에 모이도록 저장하는 구조의 테이블을 말한다. 
        - 클러스터 테이블을 이용하면, 여러테이블의 레코드를 심지어 하나의 물리적 공간에 같이 저장할 수 있다 
        - 여러 테이블들을 서로 조인된 상태로 저장해 두는 것이다. 
       
         * 단점은 DML 속도가 상당히 느려진다. 

     ⑵ 클러스터 테이블의 종류 2가지 
         ① 인덱스 클러스터 테이블 
               - 단일 테이블 인덱스 클러스터 
               - 다중 테이블 인덱스 클러스터

         ② 해쉬 클러스터 테이블 

     ⑶ 단일 클러스터 
         - 클러스터 인덱스는 컬럼 값을 하나만 저장하기 때문에 인덱스의 크기가 크지 않아 검색속도가 높아진다.
         - 클러스터 테이블은 클러스터 키값에 따라서 최대한 같은 블럭안에 같은 키값들을 저장히기 때문에 검색속도가 높아진다. 

       
     ⑷ 단일 클러스터 테이블 생성 테스트 
     
            ① 클러스터를 생성한다. 
     
                 CREATE CLUSTER objs_cluster# (object_type VARCHAR2(20) ) INDEX ;
                                                  ㅣ                           ㅣ
                                           클러스터 이름             클러스터 key 값
                                             
            ② 클러스터 인덱스를 생성한다.
               CREATE INDEX objs_cluster_idx ON CLUSTER objs_cluster# ;
                                               ㅣ                                   ㅣ 
                                       클러스터 인덱스 이름            클러스터 이름

            ③ 클러스터 테이블을 생성한다.
                CREATE TABLE objs_cluster
                  CLUSTER objs_cluster# (object_type)
                            AS SELECT *
                                  FROM all_objects
                                ORDER BY DBMS_RANDOM.VALUE;

               * dbms_random.value를 사용해서 정렬해서 데이터를 저장하면 
                   실제로 논리적으로는 object_type 별로 저장되어있지 않고 데이터가 무분별하게 흩어져서 저장되어져있는 것처럼 보이겠지만
                   실제로 물리적으로는 object_type 별로 같은 블럭안에 데이터가 저장된다.                    

                * 생성시에는 cluster, table 모두 create 하지만 truncate 시에는 cluste만 truncate 하면 자동으로 table의 내용이 삭제 된다. 
                   drop시에는 table, cluster 모두 삭제 해야 한다.

                * 클러스터 테이블을 생성하기 위해서는 클러스터 생성시 클러스터 키값은 기존 테이블의 컬럼의 데이터 타입과 길이의 범위가 같아야 한다. 
                   그렇지 않을 시 클러스터 테이블 생성시 error가 발생한다. 
 
            ④ 일반 테이블과 클러스터 테이블의 성능을 비교한다. 
 
               CREATE TABLE objs_regular
                      AS SELECT *
                             FROM objs_cluster
                          ORDER BY DBMS_RANDOM.VALUE;

               CREATE INDEX objs_regular_idx ON objs_regular(object_type) ;

               ALTER TABLE objs_regular MODIFY object_name NULL;
               ALTER TABLE objs_cluster MODIFY object_name NULL;
  
       결과 )  -- consistent gets , physical read  순 

                   SELECT *
                     FROM objs_regular
                   WHERE object_type='TABLE';
                     -- 429
                     -- 235
                     -- full table access

                    SELECT /*+ index(objs_regular objs_regular_idx) */*
                     FROM objs_regular
                   WHERE object_type='TABLE';
                      -- 549
                      -- 235 
                      -- index range scan 

                  SELECT *
                    FROM objs_cluster
                 WHERE object_type ='TABLE';
                     -- 226
                     -- 199
                     -- index unique scan 
                     -- table access cluster 

                 
    5) 다중 클러스터 테이블 
         - 여러 테이블의 레코드를 물리적으로 같은 블럭안에 저장되게 하는 테이블을 말한다. 
         - 즉, 여러테이블들을 서로 조인된 상태로 저장해두는 것을 말한다.      
        

      ⑴ 다중 클러스터 테이블 구현 
          ① 클러스터를 생성한다. 
              create cluster c_deptno# on ( deptno number(20) ) index  ;
           
          ② 클러스터 인덱스를 생성한다. 
             create index i_deptno# on cluster c_deptno# ;

          ③ 클러스터 테이블을 생성한다. 
              create table emp_cluster
                cluster c_deptno#(deptno)   -----------------------> 같은 클러스터 사용 
                 as select * 
                       from emp ;

           
             create table dept_cluster
                cluster c_deptno#(deptno)   -----------------------> 같은 클러스터 사용 
                 as select * 
                       from dept ;

              * 두개의 테이블이 같은 블럭안에 존재한다는 것을 확인해보시오 ! 

                  break on deptno skip 1 ;

                  select d.deptno, e.empno, e.ename,
                            dbms_rowid.rowid_block_number(d.rowid) deptno_block_no,
                            dbms_rowid.rowid_block_number(e.rowid) emp_block_no     
                   from dept_cluster d , emp_cluster e
                   where e.deptno = d.deptno
                   order by d.deptno ;
    

          ④ 일반 테이블과 클러스터 테이블과 성능을 비교한다. 

             select e.ename, d.loc, e.sal, e.hiredate, d.dname, e.deptno, e.mgr
                 from emp e, dept d
                where e.deptno = d.deptno and d.loc ='DALLAS';
               
                  * 순서대로 1회 실행과 2회 실행 시 

                  -- 11  -> 7
                  -- 4   -> 0
                  -- table acess full
                  -- hash join

            select e.ename, d.loc, e.sal, e.hiredate, d.dname, e.deptno, e.mgr
                 from emp_cluster e, dept_cluster d
                where e.deptno = d.deptno and d.loc ='DALLAS';

                -- 26 -> 10
                -- 6  -> 0
                -- table access cluster
                -- table acess full
                -- nested loop


문제 34. 사원 번호가 7788 번인 사원의 모든 컬럼의 데이터를 가져오는 쿼리의 성능을 emp 와 emp_iot 로 비교하시오 

 SELECT /*+ full(emp) */ *
 from emp
 WHERE empno=7788 ;
 -- consistent gets 4 
 -- full table scan 


 select *
 from emp_iot
 WHERE empno=7788 ;
 -- consistent gets 1 
 -- index unique scan 


문제 35. rn 이라는 컬럼이 있는 sales500 테이블을 rn 컬럼을 primary key 로 해서 iot를 생성하는데  이름을 sales500_iot로 구현하시오 ! 

1) rn 컬럼 추가 

CREATE TABLE SALES500
  AS SELECT ROWNUM rn, b.*
       FROM SALES b ;

2) IOT 구성 

CREATE TABLE sale500_iot
  (RN ,PROD_ID, CUST_ID, TIME_ID, CHANNEL_ID, PROMO_ID, QUANTITY_SOLD, AMOUNT_SOLD,
   CONSTRAINT sale500_iot_pk PRIMARY KEY(rn) )
   organization index
            as
             select * from sales500  ;


문제 36. 아래의 쿼리의 검색 속도를 비교하시오! 

 select *
 from sales500
where rn = 384756 ;
-- consistent gets 5076
-- full table scan 

select *
 from sale500_iot
where rn = 384756 ;
-- consistent gets 3
-- index unique scan 

* rn 컬럼에 primary key가 걸려 있기 때문에 자동으로 unique index가 생성되었다. 


문제 37. sales500 table + sales500_rn index 와 sales500_iot table 의 크기 차이를 비교하시오 ! 

SELECT segment_name, segment_type, bytes/1024/1024 MB
 FROM user_segments
 WHERE segment_name LIKE 'SALE%' ;

- sales500 (table) + sales500_rn_pk(index) = 41 + 16 = 57
- sales500_iot_pk = 39 


문제 38. SALES500 테이블과 SALES500_IOT 테이블에 insert 할 때의 속도 차이를 비교해보시오! 
- 행의 갯수 918843

첫 실험 
- sales500  : 7 초
- sales500_IOT :31 초

* 사람들 마다 차이가 있어서 여러번 실험해보아야 한다. 
* 여러번 실험할 수록 차이는 줄어 든다. 그 이유는 insert 시에 high water mark를 높여 놨기 때문이다.
* 제대로 실험해보기 위해서는 해당 table을 drop 한 후 다시 생성하고 buffer cache를 지우고 실험해보아야 한다.  


문제 39. sales500  테이블을 클러스터 테이블로 구성하는데 클러스터 키컬럼을 amount_sold로 해서 생성하시오 ! 

 CREATE CLUSTER sales500_cluster# (amount_sold VARCHAR2(22) ) INDEX ;

 CREATE INDEX sales500_cluster_idx ON CLUSTER sales500_cluster# ;

  CREATE TABLE sales500_cluster
     CLUSTER sales500_cluster# (amount_sold)
           AS SELECT *
                FROM sales500
              ORDER BY DBMS_RANDOM.VALUE;

  CREATE TABLE sales500_regular
          AS SELECT *
        FROM sales500_cluster
       ORDER BY DBMS_RANDOM.VALUE;

  CREATE INDEX sales500_regular_idx ON sales500_regular(amount_sold) ;


문제 40. sales500 테이블과 sales500_cluster 테이블과 성능을 비교하시오 

* 각각 실험 마다 flush buffer_cache 실행 
* 1차, 2차 실행 

select /*+ full(sales500_regular) */*
 from sales500_regular
where amount_sold=136.64 ;
-- 5079 -> 5079
-- 5070 -> 5069


select /*+ index(sales500 sales500_regular_idx) */ *
 from sales500_regular
where amount_sold=136.64 ;
-- 94 -> 90
-- 88 -> 0

select *
 from sales500_cluster
 where amount_sold=136.64 ;
-- 9   -> 9
-- 3   -> 0


문제 41. 아래의 조인문장의 성능이 좋아지도록 SALES 테이블과 PRODUCTS 테이블을 다중 클러스터 테이블과 구성하시오 ! 

create table sales                                    create table products
 as                                                             as 
     select * from sh.sales ;                           select * from sh.products ;

select  /*+ leading(p s) use_nl(p) */ p.prod_name, sum(s.amount_sold) 
   from sales s, products p 
 where s.prod_id = p.prod_id 
    and p.prod_id = 40
  group by p.prod_name ;

-- 4597  ->  4441
-- 4576   -> 4433
-- table acess full 
-- table acess full 
-- hash join 

 SELECT p.prod_name, sum(s.amount_sold)
   from sales_cluster s, product_cluster p
 where s.prod_id = p.prod_id
    and p.prod_id = 40
  group by p.prod_name ;
  -- 1238 -> 244
  -- 619  -> 0
  -- TABLE ACCESS CLUSTER -> INDEX UNIQUE SCAN
  -- TABLE ACCESS CLUSTER -> INDEX UNIQUE SCAN
  -- NESTED LOOPS


* 점심시간 문제 :

  create table emp_iot2
  (empno, ename, job, mgr, hiredate, sal, comm, deptno,
   CONSTRAINT emp_iot2_pk PRIMARY KEY (empno,ename) )
    organization INDEX
    INCLUDING sal
    OVERFLOW tablespace ts01
     as
    select * from emp  ;

-- 조회를 * 로 함 
-- where 조건 including 밖

   SELECT *
     FROM emp_iot
     WHERE deptno = 10;
   -- 5

   SELECT *
    FROM emp_iot2
     WHERE deptno = 10 ;
   -- 7 

-- 조회를 * 로 함 
-- where 조건 including 안

    SELECT *
     FROM emp_iot
     WHERE job = 'SALESMAN';
   -- 5

   SELECT *
    FROM emp_iot2
     WHERE job = 'SALESMAN';
    -- 7

-- 조회를 * 로 함 
-- where 조건 PK 컬럼
 
    SELECT *
     FROM emp_iot
     WHERE empno = 7788;
     -- 1

   SELECT *
     FROM emp_iot2
     WHERE empno = 7788;
     -- 3

* 아래부터는 할 때마다 alter system flush buffer_cache ; (buffer cache 내용 지우기) 를 실행함 
* 그래서 consistent get, physical read 둘다 기록 

-- where 조건 pk 컬럼
-- including 전 컬럼까지 조회

    SELECT empno, ename, job
     FROM emp_iot
     WHERE empno = 7788;
     -- 1
     -- 8

    SELECT empno, ename, job
     FROM emp_iot2
     WHERE empno = 7788 ;
    -- 7
    -- 6

-- where 조건 pk 컬럼 x
-- including 전 컬럼까지 조회

   SELECT empno, ename, job
     FROM emp_iot
     WHERE deptno = 10;
   -- 10
   -- 6

   SELECT empno, ename, job
    FROM emp_iot2
     WHERE deptno = 10 ;
   -- 13
   -- 14

-- where 조건 pk 컬럼
-- including 이외의 컬럼까지 조회

   SELECT empno, ename, deptno
     FROM emp_iot
     WHERE empno = 7788;
   -- 1
   -- 8 

   SELECT empno, ename, deptno
    FROM emp_iot2
     WHERE empno = 7788 ;
   -- 3
   -- 16   


-- where 조건 pk 컬럼 x
-- including 이외의 컬럼까지 조회

   SELECT empno, ename, deptno
     FROM emp_iot
     WHERE deptno = 10;
   -- 10
   -- 6

   SELECT empno, ename, deptno
    FROM emp_iot2
     WHERE deptno = 10 ;
   -- 13
   -- 14


* 오늘의 마지막 문제 

SALES500_IOT 와 SALES_CLUSTER 와 SALES 테이블 3개의 DML 속도를 비교하시오 !

* 모두 truncate 로 아무 것도 없던 상태에서 작업 
* db도 테스트하기 전에 startup force 실행 
* 각 테스트가 끝나면 flush buffer_cache 후 다시 테스트 진행함 

INSERT INTO SALEs500
  SELECT *
  FROM sales500_backup ;
-- 5초 13

INSERT INTO sales500_iot
  SELECT *
  FROM sales500_backup ;
-- 26초 71

INSERT INTO sales500_cluster
  SELECT *
  FROM sales500_backup ;
-- 45초 59 

* sales500 에도 sales500_iot와 동일한 조건을 주기 위해서 rn 컬럼에 pk 제약을 건 후 다시 테스트 
* 이번에는 좀 더 정확한 결과를 위해서 각 테스트 마다 startup 을 새로함 

INSERT INTO SALEs500
  SELECT *
  FROM sales500_backup ;
-- 5초 07

INSERT INTO sales500_iot
  SELECT *
  FROM sales500_backup ;
-- 22초 71

INSERT INTO sales500_cluster
  SELECT *
  FROM sales500_backup ;
-- 40초 49 

- 조금 씩 위의 결과보다 차이는 나지만 큰 차이는 발생하지 않았다. 


+ Recent posts