인덱스(Index)의 기초
인덱스
- 양방향 링크가 되어있으므로, range scan이 가능
B*트리 인덱스
- 가장 기본적인 인덱스
비트맵 인덱스
- DML이 덜 일어나도록 하는 DW(data warehouse)
- and와 or이 많은 경우
- cardinality를 줄여야 할 경우
USER01@orcl2> select count(*) from custs;
COUNT(*)
----------
55500
USER01@orcl2> select count(*) from sales;
COUNT(*)
----------
918843
USER@orcl2> select count(distinct(cust_city)) from custs;
COUNT(DISTINCT(CUST_CITY))
--------------------------
620
-- 620개의 비트맵을 만들어야 하므로, 인덱스의 사이즈가 작지는 않다.
USER01@orcl2> select sum(amount_sold)
from sales s, custs c
where s.cust_id = c.cust_id
and cust_city = 'Berlin';
USER01@orcl2> @xplan
-- HASH 조인을 진행하고 테이블 풀 스캔을 한다는 것을 알 수 있다.
USER01@orcl2> select sum(amount_sold)
from sales s, custs c
where s.cust_id = c.cust_id
and cust_city = 'Berlin';
USER01@orcl2> @xplan_all
---------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:04.73 | 5563 | 4431 | | | |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:04.73 | 5563 | 4431 | | | |
|* 2 | HASH JOIN | | 1 | 11652 | 318 |00:00:04.73 | 5563 | 4431 | 1036K| 1036K| 1185K (0)|
|* 3 | TABLE ACCESS FULL| CUSTS | 1 | 90 | 50 |00:00:00.01 | 1128 | 0 | | | |
| 4 | TABLE ACCESS FULL| SALES | 1 | 918K| 918K|00:00:01.21 | 4435 | 4431 | | | |
----------------------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.1')
DB_VERSION('11.2.0.1')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
FULL(@"SEL$1" "C"@"SEL$1")
FULL(@"SEL$1" "S"@"SEL$1")
LEADING(@"SEL$1" "C"@"SEL$1" "S"@"SEL$1")
USE_HASH(@"SEL$1" "S"@"SEL$1")
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("S"."CUST_ID"="C"."CUST_ID")
3 - filter("CUST_CITY"='Berlin')
USER01@orcl2> create bitmap index cust_sales_bji
on sales(c.cust_city)
from sales s, custs c
where c.cust_id = s.cust_id;
USER01@orcl2> select sum(amount_sold)
from sales s, custs c
where s.cust_id = c.cust_id
and cust_city = 'Berlin';
USER01@orcl2> @xplan_all
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.01 | 282 | 281 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.01 | 282 | 281 |
| 2 | TABLE ACCESS BY INDEX ROWID | SALES | 1 | 1511 | 318 |00:00:00.01 | 282 | 281 |
| 3 | BITMAP CONVERSION TO ROWIDS| | 1 | | 318 |00:00:00.01 | 3 | 2 |
|* 4 | BITMAP INDEX SINGLE VALUE | CUST_SALES_BJI | 1 | | 1 |00:00:00.01 | 3 | 2 |
----------------------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('11.2.0.1')
DB_VERSION('11.2.0.1')
ALL_ROWS
OUTLINE_LEAF(@"SEL$06E40A32")
ELIMINATE_JOIN(@"SEL$1" "C"@"SEL$1")
OUTLINE(@"SEL$1")
BITMAP_TREE(@"SEL$1" "S"@"SEL$1" AND(("CUSTS"."CUST_CITY")))
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("S"."SYS_NC00008$"='Berlin')
결합 인덱스
- 헤더가 잡히는 우선 순위
- 자주 쓰이는 존재
- = 조건으로 많이 쓰이는 존재
- distinct한 값이 더 많은 존재(좁은 범위) = cardinality가 높다
Composite Index(복합 인덱스)
- index column이 2개 이상인 인덱스
IOT
- 인덱스로 구성된 테이블
- overflow segment 가 생성되는 이유는 한 행의 크기가 블럭의 50%를 차지하는 경우 다른 블럭에 나누어 저장
- 블럭에 더 많은 행을 넣기 위함.
- ORGANIZATION INDEX TABLESPACE
- IOT Data가 저장되는 Tablespace
- PCTTHRESHOLD
- IOT를 위해서 예약된 공간의 백분율로, 1블럭의 50% 비율보다 큰 데이터가 입력되면 키 열이 아닌 데이터는 OVERFLOW TABLESPACE절에 정의된 테이블스페이스에 저장 됩니다.
- 0~50 사이값으로만 지정가능, 디폴트는 50
- INCLUDING
- IOT 행을 인덱스와 오버플로우 구역으로 나눌 열을 구분합니다.
- INCLUDING절이 지정되지 않았는데 행 크기가 PCTTHRESHOLD를 초과하면 기본 키 열을 제외한 모든 이 오버플로우 세그먼트에 저장이 됩니다.
- INCLUDING절 뒤에 있는 컬럼만 제외하고 모두 오버플로우 세그먼트에 저장이 됩니다.
- INCLUDING절에 오는 열은 기본 키의 마지막 열의 이름 이거나 기본 키가 아닌 열 입니다.
- OVERFLOW TABLESPACE
- PCTTHRESHOLD를 초과하는 Data 행이 저장됩니다.
SYS@orcl2> CREATE TABLE HR.EMP AS
SELECT EMPLOYEE_ID EMP_ID, last_name, first_name, job_id, hire_date, salary, commission_pct, email, department_id
FROM HR.EMPLOYEES ;
Table created.
SYS@orcl2> SELECT COUNT(*) FROM HR.EMP;
COUNT(*)
----------
107
SYS@orcl2> CREATE INDEX EMP_IDX ON HR.EMP(EMP_ID);
Index created.
SYS@orcl2> select * from hr.emp where emp_id between 1 and 110;
SYS@orcl2> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID b5p3q1fc46zb4, child number 0
-------------------------------------
select * from hr.emp where emp_id between 1 and 110
Plan hash value: 1472992808
-------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 11 |00:00:00.01 | 4 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 11 | 11 |00:00:00.01 | 4 |
|* 2 | INDEX RANGE SCAN | EMP_IDX | 1 | 11 | 11 |00:00:00.01 | 2 |
-------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMP_ID">=1 AND "EMP_ID"<=110)
Note
-----
- dynamic sampling used for this statement (level=2)
Elapsed: 00:00:00.06
SYS@orcl2> create table hr.emp_iot
(emp_id, last_name, first_name, job_id, hire_date, salary, commission_pct, email, department_id, constraint emp_iot_pk primary key(emp_id))
organization index
as select * from hr.emp;
Table created.
SYS@orcl2> execute dbms_stats.gather_table_stats('hr','emp_iot')
PL/SQL procedure successfully completed.
SYS@orcl2> select num_rows, blocks, avg_row_len from DBA_tables where table_name = 'EMP_IOT';
NUM_ROWS BLOCKS AVG_ROW_LEN
---------- ---------- -----------
107 50
SYS@orcl2> select index_name, blevel, leaf_blocks, clustering_factor from DBA_indexes where table_name = 'EMP_IOT';
INDEX_NAME BLEVEL LEAF_BLOCKS CLUSTERING_FACTOR
------------------------------ ---------- ----------- -----------------
EMP_IOT_PK 0 1 0
SYS@orcl2> select * from hr.emp_iot where emp_id between 1 and 110;
......
SYS@orcl2> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 0urqzs52jby30, child number 0
-------------------------------------
select * from hr.emp_iot where emp_id between 1 and 110
Plan hash value: 2733246072
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 11 |00:00:00.01 | 2 |
|* 1 | INDEX RANGE SCAN| EMP_IOT_PK | 1 | 11 | 11 |00:00:00.01 | 2 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("EMP_ID">=1 AND "EMP_ID"<=110)
SYS@orcl2> create table hr.emp_iot_new
(emp_id, last_name, first_name, job_id, hire_date, salary, commission_pct, email, department_id, constraint emp_iot_new_pk primary key(emp_id))
organization index tablespace example
overflow tablespace users
including commission_pct
as select * from hr.emp;
Table created.
SYS@orcl2> execute dbms_stats.gather_table_stats('hr','emp_iot_new')
PL/SQL procedure successfully completed.
SYS@orcl2> select num_rows, blocks, avg_row_len from DBA_tables where table_name = 'EMP_IOT_NEW';
NUM_ROWS BLOCKS AVG_ROW_LEN
---------- ---------- -----------
107 50
SYS@orcl2> select * from hr.emp_iot_new where emp_id between 1 and 110;
...
SYS@orcl2> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 7y3a6cnzqyjc0, child number 0
-------------------------------------
select * from hr.emp_iot_new where emp_id between 1 and 110
Plan hash value: 2568792030
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 11 |00:00:00.01 | 4 |
|* 1 | INDEX RANGE SCAN| EMP_IOT_NEW_PK | 1 | 11 | 11 |00:00:00.01 | 4 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("EMP_ID">=1 AND "EMP_ID"<=110)
SYS@orcl2> select emp_id, last_name, first_name, job_id, hire_date, salary, commission_pct from hr.emp_iot_new where emp_id between 1 and 110;
.....
SYS@orcl2> select * from table(dbms_xplan.display_cursor(null,null,'allstats last'));
SQL_ID 6r6c0pncyhgj2, child number 0
-------------------------------------
select emp_id, last_name, first_name, job_id, hire_date, salary,
commission_pct from hr.emp_iot_new where emp_id between 1 and 110
Plan hash value: 2568792030
----------------------------------------------------
| Id | Operation | Name | E-Rows |
----------------------------------------------------
| 0 | SELECT STATEMENT | | |
|* 1 | INDEX RANGE SCAN| EMP_IOT_NEW_PK | 11 |
----------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("EMP_ID">=1 AND "EMP_ID"<=110)
Note
-----
- Warning: basic plan statistics not available. These are only collected when:
* hint 'gather_plan_statistics' is used for the statement or
* parameter 'statistics_level' is set to 'ALL', at session or system level
SYS@orcl2> select t.table_name as iot, o.table_name as overflow,
i.index_name, o.tablespace_name as overflow_ts,
i.tablespace_name as index_ts, i.pct_threshold
from DBA_tables t, DBA_tables o, DBA_indexes i
where t.table_name = o.iot_name(+)
and t.table_name = i.table_name
AND T.TABLE_NAME IN ('EMP_IOT','EMP_IOT_NEW');
SYS@orcl2> select t.table_name as iot, o.table_name as overflow,
i.index_name, o.tablespace_name as overflow_ts,
i.tablespace_name as index_ts, i.pct_threshold
from DBA_tables t, DBA_tables o, DBA_indexes i
where t.table_name = o.iot_name(+)
and t.table_name = i.table_name
AND T.TABLE_NAME IN ('EMP_IOT','EMP_IOT_NEW');
IOT OVERFLOW INDEX_NAME OVERFLOW_TS
------------------------------ ------------------------------ ------------------------------ ------------------------------
INDEX_TS PCT_THRESHOLD
------------------------------ -------------
EMP_IOT_NEW SYS_IOT_OVER_74906 EMP_IOT_NEW_PK USERS
EXAMPLE 50
EMP_IOT EMP_IOT_PK
USERS 50
Unusable INDEX
- Userable의 반댓말은 Valid
1. UNUSABLE INDEX
USER01@orcl2> create table t1 (a number, b char(1000));
Table created.
USER01@orcl2> insert into t1
select level , dbms_random.string('L',10)
from dual
connect by level <=500;
500 rows created.
USER01@orcl2> create index t1_idx on t1(a) ;
Index created.
==========================================================================================
DBMS_RANDOM 패키지내 함수
RANDOM : 랜덤한 숫자 생성
VALUE : 랜덤한 숫자 생성(지정한 범위에서, 디폴트: 0-1)
STRING : 랜덤한 문자열 생성(문자열의 구성은 첫번째 인수값으로 지정.)
첫번째 인수값
U - 대문자
L - 소문자
A - Alphanumeric
X - Alphanumeric (대문자로 된)
P - 출력가능한 문자로만
두번째 인수값 - 문자열길이 지정
==========================================================================================
USER01@orcl2> select * from t1;
USER01@orcl2> select segment_name,extent_id, bytes/1024 kb, blocks
from user_extents
where segment_name like 'T1%';
SEGMENT_NAME EXTENT_ID KB BLOCKS
------------------------- ---------- ---------- ----------
T1 0 64 8
T1 1 64 8
T1 2 64 8
T1 3 64 8
T1 4 64 8
T1 5 64 8
T1 6 64 8
T1 7 64 8
T1 8 64 8
T1 9 64 8
T1_IDX 0 64 8
-- extent 10개
-- index 1개
USER01@orcl2> select index_name , status
from user_indexes
where table_name = 'T1';
INDEX_NAME STATUS
------------------------------ --------
T1_IDX VALID
USER01@orcl2> delete from t1
where mod(a,2)=1;
250 rows deleted.
USER01@orcl2> commit;
Commit complete.
USER01@orcl2> select segment_name, extent_id, bytes/1024 kb, blocks
from user_extents
where segment_name ='T1';
SEGMENT_NAME EXTENT_ID KB BLOCKS
------------------------- ---------- ---------- ----------
T1 0 64 8
T1 1 64 8
T1 2 64 8
T1 3 64 8
T1 4 64 8
T1 5 64 8
T1 6 64 8
T1 7 64 8
T1 8 64 8
T1 9 64 8
-- 반을 지웠는데 왜 extent는 지우기 전과 갯수가 같을까?
-- 이유는 block안의 record는 지워졌지만, HWM는 그대로 있기 떄문.
-- 이럴때 검색 속도를 향상시키기 위해서는 move를 해야한다.
USER01@orcl2> alter table t1 move;
Table altered.
USER01@orcl2> select segment_name,extent_id, bytes/1024 kb, blocks
from user_extents
where segment_name like 'T1%';
SEGMENT_NAME EXTENT_ID KB BLOCKS
------------------------- ---------- ---------- ----------
T1 0 64 8
T1 1 64 8
T1 2 64 8
T1 3 64 8
T1 4 64 8
T1 5 64 8
T1_IDX 0 64 8
7 rows selected.
-- 테이블은 줄어들었고,인덱스 세그먼트 익스텐트 보이지 않는다.
-- unusable 되면 공간을 회수해 준다.
-- 원래는 명단에 T1_IDX가 안보여야 정상...
USER01@orcl2> select index_name , status
from user_indexes
where table_name = 'T1';
INDEX_NAME STATUS
------------------------------ --------
T1_IDX UNUSABLE
-- 인덱스 상태만 남겨놓는다
USER01@orcl2> select * from t1 where a=10; --TAF --> IRS
USER01@orcl2> alter index t1_idx rebuild nologging;
Index altered.
USER01@orcl2> select index_name , status
from user_indexes
where table_name = 'T1';
INDEX_NAME STATUS
------------------------------ --------
T1_IDX VALID
INVISIBLE INDEX
- Unusable Index와는 다르게 DML 작업을 하면 Invisible Index들은 계속 유지
- 옵티마이저에게 invisible 인덱스 사용을 고려하지 않도록 한다.
- 인덱스를 삭제하기 전에 테스트 하는 용도로도 사용
- 동일한 컬럼에 다른 유형의 인덱스를 만들어서 테스트하기 위해서도 사용
2. INVISIBLE INDEX
USER01@orcl2> alter index t1_idx invisible;
Index altered.
USER01@orcl2> set autot on explain
USER01@orcl2> select *
from t1
where a=10;
Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1015 | 13 (0)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| T1 | 1 | 1015 | 13 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("A"=10)
Note
-----
- dynamic sampling used for this statement (level=2)
USER01@orcl2> alter index t1_idx visible;
Index altered.
USER01@orcl2> select *
from t1
where a=10;
Execution Plan
----------------------------------------------------------
Plan hash value: 546753835
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 1015 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 1015 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T1_IDX | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("A"=10)
Note
-----
- dynamic sampling used for this statement (level=2)
가상 컬럼
- 가상 컬럼은 테이블에있는 하나 이상의 컬럼값을 기반으로
- 계산식을 적용할 수 있는 11g의 기능이다.
- 물리적인 공간을 차지 하지 않고 메타데이터로만 저장된다.
- 파티션 테이블 사용 시 마땅치 않는 컬럼이 없을 경우 가상 컬럼을 통해 적용 가능하다.
- 가상 컬럼에 인덱스(함수 기반 인덱스) 생성이 가능하며, 통계 정보 수집도 가능하다.
- 가상 컬럼에는 데이터를 직접 INSERT 할 수 없다.
emp2 sal 값을 통해 사원의 급여 등급 계산하는 가상 열 추가하는 테스트
(1)기존 테이블에 가상 컬럼 추가
USER01@orcl2> alter table emp2 add
(grade varchar2(1) generated always as (
case when sal<= 2000 then 'D'
when sal > 2000 and sal <= 3000 then 'C'
when sal > 3000 and sal <= 4000 then 'B'
else 'A' end) virtual);
Table altered.
(2)테스트
USER01@orcl2> select * from emp2;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO G(가상열)
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- -
7369 SMITH CLERK 7902 17-DEC-80 800 20 D
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 D
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 D
7566 JONES MANAGER 7839 02-APR-81 2975 20 C
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30 D
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30 C
7782 CLARK MANAGER 7839 09-JUN-81 2450 10 C
7788 SCOTT ANALYST 7566 19-APR-87 3000 20 C
7839 KING PRESIDENT 17-NOV-81 5000 10 A
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30 D
7876 ADAMS CLERK 7788 23-MAY-87 1100 20 D
7900 JAMES CLERK 7698 03-DEC-81 950 30 D
7902 FORD ANALYST 7566 03-DEC-81 3000 20 C
7934 MILLER CLERK 7782 23-JAN-82 1300 10 D
14 rows selected.
USER01@orcl2> desc emp2 -- grade 보인다.
Name Null? Type
------------------------------------------------------------------------ -------- --------
EMPNO NUMBER(4)
ENAME VARCHAR2(10)
JOB VARCHAR2(9)
MGR NUMBER(4)
HIREDATE DATE
SAL NUMBER(7,2)
COMM NUMBER(7,2)
DEPTNO NUMBER(2)
GRADE VARCHAR2(1)
USER01@orcl2> select empno, sal, grade from emp2;
USER01@orcl2> desc emp2
USER01@orcl2> insert into emp2 (empno , grade)
values (9000,'A'); --err
insert into emp2 (empno , grade)
*
ERROR at line 1:
ORA-54013: INSERT operation disallowed on virtual columns
-- 가상열에 추가는 되지 않는다.
USER01@orcl2> insert into emp2 (empno , sal)
values (9000,5000);
1 row created.
USER01@orcl2> select * from emp2;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO G
---------- ---------- --------- ---------- --------- ---------- ---------- ---------- -
7369 SMITH CLERK 7902 17-DEC-80 800 20 D
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300 30 D
7521 WARD SALESMAN 7698 22-FEB-81 1250 500 30 D
7566 JONES MANAGER 7839 02-APR-81 2975 20 C
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400 30 D
7698 BLAKE MANAGER 7839 01-MAY-81 2850 30 C
7782 CLARK MANAGER 7839 09-JUN-81 2450 10 C
7788 SCOTT ANALYST 7566 19-APR-87 3000 20 C
7839 KING PRESIDENT 17-NOV-81 5000 10 A
7844 TURNER SALESMAN 7698 08-SEP-81 1500 0 30 D
7876 ADAMS CLERK 7788 23-MAY-87 1100 20 D
7900 JAMES CLERK 7698 03-DEC-81 950 30 D
7902 FORD ANALYST 7566 03-DEC-81 3000 20 C
7934 MILLER CLERK 7782 23-JAN-82 1300 10 D
9000 5000 A
인덱스는 어떻게 만들고 관리해야하는가? : 지침
- 대량의 데이터를 삽입할 때는 삽입을 하면서 인덱스를 생성하는게 아닌, 전부 삽입이 된 이후 생성한다.
- 하지만, 기존의 데이터가 많을 경우, 이 방법은 좋지 않다.
- 올바른 테이블과 열을 인덱스화
- UNIQUE하면 할수록 좋다.
- 조인에 사용되는 열을 인덱스 하면 좋다
- 작은 테이블은 인덱스 하지 않는다.
- 인덱스에 적합한 열
- 넓은 범위의 값( = distinct가 많다) : 일반적인 인덱스
- 작은 범위의 값( = distinct의 값이 적다) : 비트맵 인덱스
- 대량의 데이터의 경우 null로 저장
- 성별 컬럼에서 남자 99% 여자1%일 경우 남자 99%(대량의 데이터)는 null로 되고, 여자 1%가 저장된다.
- where gender = female이면 'female' 인 값을 빠르게 찾는다
- where gender = male이면 null인 값을 full scan을 하여 빠르게 찾는다.
- 인덱스에 적합하지 않은 열
- 많은 null이 있는데, not null에 대하여 검색하지 않는 경우
- 가상열
'DATABASE(oracleDB 11g) > Tuning' 카테고리의 다른 글
[SQL Tuning]Subquery operation(서브쿼리 오퍼레이션) (0) | 2019.05.20 |
---|---|
[SQL Tuning]Join operation(조인 오퍼레이션) (0) | 2019.05.20 |
[SQL Tuning]인덱스를 사용하지 못하는 사례 6가지와 해결책 (0) | 2019.05.03 |
[SQL Tuning]옵티마이저 연산자 (0) | 2019.05.03 |
[SQL Tuning]실행계획 (0) | 2019.05.03 |