1-1 인덱스 분리형

  • 1) 테이블과 인덱스가 별도로 구분되어 있는 관계형 데이타베이스의 가장 일반적인 저장형태이다.
  • 2) 데이터 저장시 테이터 값에 무관하게 임의의 위치에 저장하여 저장에 따른 부담이 최소화 된다. 대신 인덱스의 ROWID에 데이터의 물리적 위치를 저장하여 언제라도 엑세스가 가능하다.
  • 3) ROWID는 ObjectNo+DatafileNo+BlockNo+SlotNo로 구성되어 있으며 슬롯번호에는 데이타가 들어 있는 물리적 위치가 저장되어 있다.
  • 데이터 Migration,Condensing등으로 인해 데이터의 물리적 위치가 변경되면 슬롯에 있는 위치정보만 바꾸어 주면 되므로 ROWID는 변함이 없다.


1-2 인덱스 일체형

1. 일체형 테이블 생성구문

CREATE TABLE DOCUMENTS (
	DOC_ID VARCHAR2(5),
	TITLE VARCHAR2(50),
	AUTHOR VARCHAR2(20),
	CONTENTS VARCHAR2(2000),
	STATUS VARCHAR2(2),
	CONSTRAINT PK_DOC PRIMARYKEY (DOC_ID)
)
ORGANIZATION INDEX			---(A)
TABLESPACE DATA01			---(B)			
PCTTHRESHOLD 20		         ---(C)
INCLUDING CONTENTS			---(D)
OVERFLOW TABLESPACE IDX01	         ---(E)
;


  • (A) : 일체형 테이블로 생성
  • (B) : 데이터가 저장될 테이블 스페이스 지정
  • © : 단일 로우의 크기가 (PCTTHRESHOLD/100)*DB_BLOCK_SIZE 보다 크면 INCLUDING 이후의 칼럼들은 오버플로우 영역으로 저장된다. 만일 오버플로우 영역이 지정되어 있지 않으면 저장이 거부된다.
  • (D) : 오버플로우 영역에 저장될 칼럼을 지정한다. 만일 INCLUDING 지정하지 않았는데 로우가 크다면 기본키를 제외한 모든 칼럼이 오버플로우 영역에 저장된다. 만일 INCLUDING 이후의 칼럼에 데이터가 입력되지 않으면 모든 칼럼은 인덱스 영역에 저장된다.
  • (E) : 로우가 클 경우 INCLUDING 이후의 칼럼이 저장될 테이블 스페이스. 이를 지정하지 않으면 로우가 클 경우 저장이 거부된다.


2. 장점
  • 1) 기본키와 기본키가 아닌 데이타가 함께 저장되어 있으며 기본키로 정렬되어 있으며 이는 엄청난 잇점을 준다. (?)이펙티브 540페이지 상단 : 그러나 키 자체는 정렬되지 않은 상태로 저장된다.
  • 2) (?)이펙티브 540페이지 상단 : IOT는 두세가지 구현 영역에 있어서 매우 유용하다. 그중 하나가 연관 테이블, 즉 다대다 관계에서 사용되는 테이블이다.
  • 3) 인덱스가 없기 때문에 한번의 논리적인 엑세스가 줄어들었을뿐 아니라 인덱스에서 테이블로의 랜덤 엑세스가 없기 때문에 넓은 범위의 검색에 탁월한 효과를 지닌다.
  • 4) 리프노드에 기본키를 포함한 모든 데이타가 저장되는 형태이므로 데이터의 수정에 따른 크기 증가시 노드가 분할하게 되어 어떤 키값이 동일한 노드에 지속적으로 저장되어 있을 수 없다. 이러한 한계때문에 영구적인 물리적 주소를 가질 수 없으며 따라서 ROWID가 없다. 이러한 단점을 보완하기 위해 논리적 ROWID라는 것을 지원하지만 이것은 처음 로우가 생성될 때 만들어진 것으로 반드시 그 위치에 로우가 있다는 걸 보장하지 못한다. 그러므로 데이터를 엑세스할 때 논리적 ROWID가 부정확할 확률이 높다고 판단되면 기본키로의 엑세스로 환원하게 된다.


3. 단점
  • 1) 추가적인 인덱스가 생성이 불가능하여 오직 기본키로만 엑세스해야 한다는 단점은 인덱스의 추가허용으로 어느정도 극복되었지만 아직도 다양한 엑세스를 해야 하는 경우는 매우 불리하다.
  • 2) 저장시 반드시 정해진 위치에 들어가야 하기 때문에 입력 속도가 느리다.
  • 3) 입력되는 데이터의 크기가 클 경우 일부 칼럼이 오버플로우 영역에 저장되거나 아니면 입력 자체가 거부될 수 있다는 점을 항상 고려해야 한다. 그러나 입력되는 로우가 항상 일정한 크기로 들어오는 경우는 기대하기는 힘들다.


4. 일체형 구조를 적용하기 좋은 테이블
  • 1) 검색용 테이블
  • 2) 코드성 테이블
  • 3) 대부분 기본키로 검색되는 테이블
  • 4) OLAP의 디멘젼 테이블
  • 5) 로우의 길이가 짧고 트랜잭션이 빈번하게 발생되지 않는 테이블


2. IOT로 공간절약하기



1) 인덱스 일체형 테이블 생성
CREATE TABLE T (
	A INT
	,B INT
	,PRIMARY KEY (A,B)
)
ORGANIZATION INDEX

2) 보조인덱스 생성
CREATE INDEX T_IDX ON T(B)

3)쿼리문 실행

SQL> SET AUTOTRACE TRACEONLY EXPLAIN
SQL> SELECT A,B FROM T WHERE B=55;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=1 Card=1 Bytes=26)
   1    0   INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE) (Cost=1 Card=1Bytes=26)

4) 해설
B칼럼에 설정된 T_IDX 인덱스가 사용되었고 SELECT절에 A칼럼에 대한 요청이 있슴에도 불구하고 
[TABLE ACCESS BY ROWID]에 의한 테이블 엑세스가 나타나지 않고 있다. 
이는 인덱스구조의 논리적인 ROWID로 부터 칼럼 A의 값을 얻을 수 있다는 사실을 알고 있기에 테이블 엑세스를 하지 않은 것이다. 
이처럼 보조 인덱스를 생성하여 디스크 공간을 절약할 수 있다.

5) 만일 분리형 테이블이었다면 다음과 같이 테이블을 생성해야 테이블 엑세스가 발생하지 않을 것이다.

CREATE TABLE T (
A INT
,B INT
,PRIMARY KEY (A,B)
)

/*T_IDX 인덱스를 B,A 두개의 칼럼에 만든다*/
CREATE INDEX T_IDX ON T(B,A)

SQL>  SELECT A,B FROM T WHERE B=55;

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE)



3. IOT로 입력 데이타 한데 모으기



1.테이블 생성

CREATE TABLE IOT (
USERNAME VARCHAR2(30),
DOCUMENT_NAME VARCHAR2(30),
OTHER_DATA CHAR(100),
CONSTRAINT IOT_PK PRIMARY KEY (USERNAME,DOCUMENT_NAME)
)
ORGANIZATION INDEX

CREATE TABLE HEAP (
USERNAME VARCHAR2(30),
DOCUMENT_NAME VARCHAR2(30),
OTHER_DATA CHAR(100),
CONSTRAINT HEAP_PK PRIMARY KEY (USERNAME,DOCUMENT_NAME)
)

2.데이터입력

BEGIN
	 FOR I IN 1..100
	 LOOP
	 	 
		 FOR X IN (SELECT USERNAME FROM ALL_USERS)
		 LOOP
		 	 
			 INSERT INTO HEAP (USERNAME,DOCUMENT_NAME,OTHER_DATA)
			 VALUES
			 (X.USERNAME,X.USERNAME||'_'||I,'X');
			 
			 INSERT INTO IOT (USERNAME,DOCUMENT_NAME,OTHER_DATA)
			 VALUES
			 (X.USERNAME,X.USERNAME||'_'||I,'X');
		 END LOOP;
		 
	 END LOOP;
	 COMMIT;
END;
/

3.데이터출력

DECLARE
	   TYPE T_ARRAY IS TABLE OF VARCHAR2(100);
	   ARRAY1 T_ARRAY;
	   ARRAY2 T_ARRAY;
	   ARRAY3 T_ARRAY;
BEGIN
	 FOR I IN 1..10
	 LOOP
	 	 
		 FOR X IN (SELECT USERNAME FROM ALL_USERS)
		 LOOP
		 	 
			 FOR Y IN (SELECT * FROM HEAP SINGLE_ROW WHERE USERNAME=X.USERNAME)
			 LOOP
			 	 NULL;
			 END LOOP;
			 
			 FOR Y IN (SELECT * FROM IOT SINGLE_ROW WHERE USERNAME=X.USERNAME)
			 LOOP
			 	 NULL;
			 END LOOP;
			 
			 SELECT * BULK COLLECT INTO ARRAY1,ARRAY2,ARRAY3
			 FROM HEAP BULK_COLLECT
			 WHERE USERNAME=X.USERNAME;
			 
			 SELECT * BULK COLLECT INTO ARRAY1,ARRAY2,ARRAY3
			 FROM IOT BULK_COLLECT
			 WHERE USERNAME=X.USERNAME;
			 
		 END LOOP;
		 
	 END LOOP;
END;
/

4.TRACE 분석

1) HEAP SINGLE_ROW 

SELECT * FROM HEAP SINGLE_ROW WHERE USERNAME=:b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute    310      0.01       0.00          0          0          0           0
Fetch    31310      0.32       0.29          0      62610          0       31000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    31621      0.34       0.30          0      62610          0       31000

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: CHOOSE
      0   TABLE ACCESS (BY INDEX ROWID) OF 'HEAP'
      0    INDEX (RANGE SCAN) OF 'HEAP_PK' (UNIQUE)

2) IOT SINGLE_ROW 

SELECT * FROM IOT SINGLE_ROW WHERE USERNAME=:b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute    310      0.00       0.00          0          0          0           0
Fetch    31310      0.26       0.26          0      31610          0       31000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total    31621      0.26       0.26          0      31610          0       31000

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: CHOOSE
      0   INDEX (RANGE SCAN) OF 'IOT_PK' (UNIQUE)

3) HEAP BULK_COLLECT 

SELECT * FROM HEAP BULK_COLLECT WHERE USERNAME=:b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute    310      0.00       0.00          0          0          0           0
Fetch      310      0.15       0.13          0      19620          0       31000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      621      0.15       0.14          0      19620          0       31000

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: CHOOSE
      0   TABLE ACCESS (BY INDEX ROWID) OF 'HEAP'
      0    INDEX (RANGE SCAN) OF 'HEAP_PK' (UNIQUE)

4) IOT BULK_COLLECT 

SELECT * FROM IOT BULK_COLLECT WHERE USERNAME=:b1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute    310      0.00       0.00          0          0          0           0
Fetch      310      0.07       0.07          0       1500          0       31000
------- ------  -------- ---------- ---------- ---------- ----------  ----------
total      621      0.07       0.07          0       1500          0       31000

Rows     Execution Plan
-------  ---------------------------------------------------
      0  SELECT STATEMENT   GOAL: CHOOSE
      0   INDEX (RANGE SCAN) OF 'IOT_PK' (UNIQUE)