2021년 11월 14일 일요일

오라클 INDEX, 오름차순/내림차순 인덱스(Ascending/Descending Index)

 

오라클 INDEX, 오름차순/내림차순 인덱스(Ascending/Descending Index)


인덱스index를 생성 할 때 칼럼명 다음에 ASC 또는 DESC를 기술하지 않으면 기본적으로 오름차순(ASCENDING)으로 인덱스가 생성되는데, 컬럼명 다음에 ASC 라고 기술하면 오름차순, DESC 라고 기술하면 내림차순(DESCENDING)으로 인덱스가 생성됩니다.


오름차순, 내림차순 인덱스 구분은 데이터 조회시 정렬(SORT) 이라는 중요한 기능을 수행 합니다.  인덱스가 내림차순으로 생성되어 있다면 인덱스를 경유하여 데이터를 조회하면 ORDER BY를 기술하지 않더라도 데이터는 내림차순 정렬되어 있을 것 입니다.


EMP 테이블의 데이터를 조회할 때 SELECT * FROM EMP 이런식으로 인덱스를 경유하지 않고 원본 테이블에서 조회 한다면 출력되는 데이터는 원본 데이터에서 입력된 순서대로 조회됩니다.


만약 전체 사원목록을 조회할 때 사원명으로 내림차순 조회하고 싶다면 대부분 다음처럼 쿼리 할 것 입니다.


SELECT * FROM EMP ORDER BY ENAME;


이때 EMP 테이블의 ename  컬럼에 인덱스가 있고 이를 경유 한다면 원본데이터를 메모리에 올려서 정렬하는 과정을 거치지 않아 다행이지만, 인덱스가 없다면 위 쿼리 구문의 실행을 위해 오라클은 해당 컬럼 값들을 메모리에 올려 정렬sort해야 하므로 대용량 테이블에서는 최악의 쿼리가 될 것 입니다. 실무에서 대용량 테이블인 경우 인덱스가 없는 컬럼에 대해서 절대 이런식으로 사용하시면 안됩니다. 


만약 인덱스가 생성되어 있다면 EMP 테이블의 데이터를 추출할 때 인덱스를 경유하도록 하면 데이터는 저절로 정렬되어 있다는 사실을 잘 생각해야 합니다. 이런 경우 일부러 ORDER BY를 사용하지 않아도 인덱스를 경유하도록 하면 데이터는 정렬되어 있을 것 입니다. 이장의 뒷부분에서 실습을 해보겠습니다.


실습에서 오름차순, 내림차순 인덱스를 생성하고 ORDER BY 구문을 사용하지 않아도 인덱스 영역을 경유 하도록 쿼리를 잘 사용하면 데이터는 정렬된다는 것을 실습해 보겠습니다.

실습


오름차순 인덱스를 생성해 보겠습니다.


EMP 테이블의 sal 컬럼에 비고유, 오름차순 인덱스를 생성하세요.


CREATE INDEX IDX_EMP_SAL ON EMP(SAL ASC);


<실행결과>

Index IDX_EMP_SAL이(가) 생성되었습니다.


컬럼명 다음에 ASC, DESC를 기술하지 않으면 ASC가 기본값 입니다. 위 구문은 다음 구문과 동일 합니다. CREATE INDEX IDX_EMP_SAL ON EMP(SAL)

실습


복합 컬럼에 오름차순, 내림차순 인덱스를 생성해 보겠습니다.


EMP 테이블에서 job 오름차순, sa 내림차순으로 인덱스를 생성 하세요.


CREATE INDEX IDX_EMP_JOB_SAL ON EMP(JOB, SAL DESC);


<실행결과>

Index IDX_EMP_JOB_SAL이(가) 생성되었습니다.


실습


테이블에 입력되는 순서대로 SELECT 시 조회된다는 사실을 실습을 통해 알아 보겠습니다.


TEST 테이블을 생성 후 3건의 데이터를 입력하고 조회해 보세요.


CREATE TABLE TEST (

A VARCHAR2(100) PRIMARY KEY,

b VARCHAR2(10));


INSERT INTO TEST VALUES ('1','111');

INSERT INTO TEST VALUES ('3','333');

INSERT INTO TEST VALUES ('2','222');


SELECT * FROM TEST;


<실행결과>


 

A

B

1

1

111

2

3

333

3

2

222


INSERT 문에 의해 입력되는 순서대로 데이터가 조회 됩니다.


실습


ORDER BY 구문을 사용하지 않고도 정렬된 데이터를 추출해 보겠습니다.

현재  EMP 테이블의 ename 컬럼은 인덱스가 생성되어 있습니다.



EMP 테이블의 모든 데이터를 조회하세요.


SELECT EMPNO, ENAME FROM EMP;


<실행결과>

 

EMPNO

ENAME

1

7369

SMITH

...

...

...

13

7902

FORD

14

7934

MILLER


EMP 테이블에 입력된 순서대로 조회 됩니다.



EMP 테이블에서 모든 사원의 empno, ename 컬럼 데이터를 조회하세요.(단 ename 오름차순으로 정렬)


SELECT EMPNO, ENAME FROM EMP ORDER BY ENAME;


<실행결과>

 

EMPNO

ENAME

1

7876

ADAMS

...

...

...

13

7844

TURNER

14

7521

WARD


ename 컬럼을 기준으로 오름차순 정렬되어 조회 됩니다.



이번에는 ORDER BY 구문을 이용하지 않고 인덱스를 경유하도록 해서 데이터를 조회해 보겠습니다.


EMP 테이블에서 모든 사원의 empno, ename 컬럼 데이터를 조회하세요.(단 ename 오름차순으로 정렬)


SELECT EMPNO, ENAME FROM EMP WHERE ENAME > 'A';


<실행결과>

 

EMPNO

ENAME

1

7876

ADAMS

...

...

...

13

7844

TURNER

14

7521

WARD


ename 컬럼을 기준으로 오름차순 정렬되어 조회 됩니다. 


ORDER BY를 사용하지 않았지만 오라클을 감동시켜 ename 인덱스를 경유 하도록 하기 위해 WHERE 절에 ename 컬럼을 일부러 출현시켰더니 오라클이 ename 인덱스를 경유하여 오름차순으로 데이터가 조회 되었습니다. 여기서 우리는 WHERE 절에 인덱스 컬럼을 출현시키면 오라클이 해당 컬럼의 인덱스 영역에서 데이터를 조회한다는 사실을 알았습니다.


사실 중요한 것은 ORDER BY를 사용했냐 안했냐가 아니라 내가 작성한 쿼리문이 적절한 인덱스를 경유하여 검색 속도에 문제가 없는지 입니다. 


ORDER BY는 인덱스가 없는 컬럼에 대해 사용하게 되면 100% 메모리에 올려 정렬이라는  과정을 거치게 되어 있으므로 대용량 테이블인 경우 조회 속도는 최악 입니다. 정말 주의 해야 합니다. 


물론 ORDER BY를 사용하더라도 컬럼에 인덱스가 있다면 원본 데이터를 정렬하는 것보다 대체로 인덱스 영역에서 데이터를 가지고 오니 큰 무리는 없습니다. 그러므로 ORDER BY를 사용했다면 오라클의 실행계획execution plan(SQL Developer에서 F12)을 반드시 확인하여 ORDER BY에 사용한 컬럼의 인덱스를 경유하는 지를 반드시 확인해야 합니다.


오라클에서 쿼리 실행전 중요한 구성요소중 하나는 오라클 옵티마이저oracle optimizer 입니다. 옵티마이저는 다양한 실행 경로를 생성하고 비용(COST)이 가장 적게드는 최적의 실행경로를 선택합니다.


실행계획은 오라클 옵티마이저(Oracle Optimizer)가 SQL문장의 실행을 위해 테이블의 데이터를 원본에서 하나씩 읽어서 접근할 것인지, 어떤 인덱스에서 랜덤 액세스를 통해 접근할 것인지, 어떤 SQL연산을 사용할 것인지, 어떤 조인순서로 조인을 하고, 어떤 조인을 사용할 것인지 등에 대해 계획을 수립한 것 입니다.

실습


이번에는 ename 컬럼의 인덱스를  내림차순으로 생성한 후 ename 내림차순으로 데이터를 조회해 보겠습니다.


ename 컬럼에 생성되어 있는 IDX_EMP_ENAME 인덱스를 삭제하고 내림차순 인덱스를 다시  생성하세요.


DROP INDEX IDX_EMP_NAME;

CREATE INDEX IDX_EMP_ENAME ON EMP(ENAME DESC);


EMP 테이블에서 모든 사원의 empno, ename 컬럼 데이터를 조회하세요.(단 ename 내림차순으로 정렬)


SELECT EMPNO, ENAME FROM EMP ORDER BY ENAME DESC;


<실행결과>

 

EMPNO

ENAME

1

7521

WARD

...

...

...

13

7499

ALLEN

14

7876

ADAMS


ename 컬럼을 기준으로 내림차순 정렬되어 있습니다.


이번에는 ORDER BY 구문을 이용하지 않고 인덱스를 경유하도록 해서 데이터를 조회해 보겠습니다.


EMP 테이블에서 모든 사원의 empno, ename 컬럼 데이터를 조회하세요.(단 ename 내림차순으로 정렬)


SELECT EMPNO, ENAME FROM EMP WHERE ENAME > 'A';


<실행결과>


 

EMPNO

ENAME

1

7521

WARD

...

...

...

13

7499

ALLEN

14

7876

ADAMS


ORDER BY를 사용하지 않았지만 WHERE절에 ename 컬럼을 출현시켜 오라클에게 ename 컬럼 인덱스를 경유하여 데이터를 추출하도록 했습니다. WHERE절에 컬럼을 출현시키는 방법이외에 오라클의 힌트 구문을 이용하여 원하는 인덱스를 경유하여 데이터를 추출하도록 할 수 있습니다.

 

#인덱스, #오름차순인덱스, #INDEX, #오라클인덱스, #오라클, #오라클강좌, #오라클교육, #ORACLE​

 

오라클 INDEX, 고유/비고유 인덱스(Unique/Non Unique Index)

 

오라클 INDEX, 고유/비고유 인덱스(Unique/Non Unique Index)


고유 인덱스unique indexes는 칼럼의 값들이 유일한 경우에 만들 수 있는 인덱스이고, 비고유 인덱스non unique indexes는 칼럼 값에 중복된 값이 있는 경우 만드는 인덱스 입니다.



다음 실습에서 고유/비고유 인덱스를 생성해 보겠습니다.

실습


이번 실습에서 생성한 두개의 인덱스를 삭제하고 고유 인덱스를 생성해 보겠습니다. DROP INDEX 명령으로 인덱스를 삭제할 수 있습니다.


IDX_ENAME, IDX_ENAME_SAL 2개의 인덱스를 삭제 하세요.


DROP  INDEX IDX_EMP_ENAME;                  

DROP  INDEX IDX_EMP_ENAME_SAL;


<실행결과>

Index IDX_EMP_ENAME이(가) 삭제되었습니다.

Index IDX_EMP_ENAME_SAL이(가) 삭제되었습니다.


EMP 테이블의 ename 컬럼에 고유인덱스를 생성하세요.


CREATE UNIQUE INDEX IDX_EMP_ENAME ON EMP(ENAME);


<실행결과>

INDEX IDX_EMP_ENAME이(가) 생성되었습니다.


현재 EMP 테이블의 ename 컬럼은 중복되는 값이 없어서 인덱스가 잘 생성 되었습니다. 만약 중복되는 값이 있다면 어떻게 될까요? 다음 실습에서 확인 하세요.


EMP 테이블에 이미 존재하는 사원인 “SMITH” 라는 이름으로 데이터를 입력하고 고유인덱스를 생성하세요. 먼저 이전에 생성한 IDX_EMP_ENAME 인덱스를 삭제하세요.


DROP INDEX IDX_EMP_ENAME;

INSERT INTO EMP(EMPNO, ENAME) VALUES (9999, 'SMITH');

CREATE UNIQUE INDEX IDX_EMP_ENAME ON EMP(ENAME);


<실행결과>

ORA-01452: 중복 키가 있습니다. 유일한 인덱스를 작성할 수 없습니다.


“SMITH”라는 이름의 사원이 중복되므로고유 인덱스를 생성 할 수 없습니다.

실습


비고유 인덱스를 생성해 보겠습니다.


EMP 테이블에서 job 칼럼에 대해 비고유인덱스(Non Unique Index)를 생성 하세요.


CREATE INDEX IDX_EMP_JOB ON EMP(JOB);


<실행결과>

Index IDX_EMP_JOB이(가) 생성되었습니다.


일반적으로 오라클의 CREATE INDEX 구문은 중복되는 값이 있더라고 인덱스를 생성하므로 대부분의 인덱스는 비고유 인덱스 입니다. 주민등록번호 처럼 값이 중복되지 않음을 확신 할 수 있는 컬럼에 대해 고유 인덱스를 생성해야 합니다.

 

#인덱스, #오라클인덱스, #고유인덱스, #유니크인덱스, #비고유인덱스, #오라클강좌, #오라클, #ORACLE​

오라클 INDEX, 단일/복합(결합) 인덱스(Single Column/Composite Index)

 

오라클 INDEX, 단일/복합(결합) 인덱스(Single Column/Composite Index)


단일 인덱스는 하나의 칼럼으로 인덱스가 구성된 것이며, 복합 인덱스는 두개 이상의 컬럼으로 인덱스가 생성된 것 입니다.


다음 실습에서 단일컬럼 및 복합 컬럼에 대해 인덱스를 생성해 보겠습니다.

실습


단일 컬럼에 대해 인덱스를 생성하고 딕셔너리 뷰dictionary view에서 생성된 인덱스를 확인합니다.


EMP 테이블의 ename 컬럼에 대해 인덱스를 생성 합니다.


CREATE INDEX IDX_EMP_ENAME ON EMP(ENAME);


<실행결과>

Index IDX_EMP_ENAME이(가) 생성되었습니다.


USER_INDEXES 뷰는 사용자가 생성한 인덱스 정보를 제공하는 딕셔너리 뷰 입니다.


생성된 인덱스를 확인 합니다.


SELECT TABLE_NAME, INDEX_NAME 

FROM USER_INDEXES 

WHERE TABLE_NAME = 'EMP';


<실행결과>

 

TABLE_NAME

INDEX_NAME

1

EMP

PK_EMP

2

EMP

IDX_EMP_ENAME


CREATE INDEX로 ename 컬럼에 하나의 인덱스를 생성했는데 왜 2건이 조회될까요? 왜냐하면 EMP 테이블을 생성할 때 empno 컬럼을 기본키primary key로 지정하고 기본키 이름을 PK_EMP 라고 지정을 해서 그 이름으로 인덱스를 생성한 것 입니다. 오라클에서 테이블의 컬럼에 대해 기본키를 지정하면 NOT NULL + UNIQUE 제약조건이 걸리고 별도의 영역에 해당 컬럼을 순서대로 정렬해서 인덱스를 생성한다는 것을 다시 한번 상기해 주세요.


실습


2개 이상의 복합 컬럼에 대해 인덱스를 생성하고 딕셔너리 뷰에서 생성된 인덱스를 확인합니다.


EMP 테이블의 ename, sal 컬럼에 대해 인덱스를 생성 합니다.


CREATE INDEX IDX_EMP_ENAME_SAL ON EMP(ENAME, SAL);


<실행결과>

Index IDX_EMP_ENAME_SAL이(가) 생성되었습니다.


생성된 인덱스를 확인 합니다.


SELECT TABLE_NAME, INDEX_NAME 

FROM USER_INDEXES 

WHERE TABLE_NAME = 'EMP';


<실행결과>

 

TABLE_NAME

INDEX_NAME

1

EMP

PK_EMP

2

EMP

IDX_EMP_ENAME

3

EMP

IDX_EMP_ENAME_SAL

 

#오라클인덱스, #인덱스, #인덱스란, #인덱스종류, #ORACLE, #ORACLE인덱스

오라클 인덱스(Oracle Index)란? 개요 및 구조, 작동방식, 필요한 이유

 

오라클 인덱스(Oracle Index)란? 개요 및 구조, 작동방식, 필요한 이유


인덱스 소개


인덱스는 테이블의 칼럼에 대해 생성되는 객체로 별도의 공간에 컬럼값들을 정렬한 후 생성 합니다. 데이터 검색 속도를 향상 시키기 위해 사용되며, 포인터를 이용하여 데이터를 랜덤 액세스random access 합니다. 예를들어 1억건 이상의 고객데이터가 있고 고객이름으로 인덱스가 생성되어 있지 않다고 했을 때  “홍길동” 고객을 검색하려면 처음 행부터 “홍길동” 고객이 출현할 때 까지 검색을 해가야 합니다. 운이 없어서 마지막 행에 “홍길동” 데이터가 있었다면 검색속도는 아주 느려질 것 입니다. 그러나 고객이름으로 인덱스가  생성되어져 있다면 랜덤 액세스로 바로 찾아 갈 수 있습니다. 이 두경우는 하늘과 땅 차이죠^^ 그만큼 인덱스는 중요하답니다.


인덱스는 한번 생성되면 오라클에 의해 내부적으로 자동 관리 됩니다.

오라클에서 Create Index로 인덱스를 생성하면 균혅바힌 트리 형태인 B*Tree(Balanced Tree) 인덱스가 생성되며 어떠한 행을 접근하든지 액세스 타임이 동일한 것이 특징 입니다. 인덱스를 생성해야 하는 컬럼은 SQL문의 WHERE절 or 조인절에 빈번히 출현되는 칼럼 입니다. 특히 칼럼값의 분포도가 10%~15% 인 경우 인덱스가 효율적 입니다. 주의할 점은 삽입, 삭제가 빈번하여 값이 자주 변경되는 테이블에는 인덱스의 사용을 자제해야 합니다. 왜냐하면 테이블의 값이 입력/수정/삭제 될 때 테이블만 갱신하는 것이 아니라 인덱스도 같이 갱신해 줘야 하기 때문 입니다.


TdPx5OfcOduK4bfrUGkk5GjNGkiFSUQKeg01mACc

[그림 12.1 인덱스구조]


사원(EMP) 테이블의 사원명(ename) 컬럼에 인덱스가 생성되어 있는 모습 입니다. USER라는 테이블스페이스에 EMP 테이블 데이터 원본이 존재하고, 인덱스는 별도의 이름을 가진 다른 테이블스페이스에 생성이 되어 있습니다. 그림의 맨 좌측 16진수 문자열 컬럼은 ROWID 컬럼으로 모든 행들은 물리적인 주소를 가리키는 의사컬럼이 입니다. 




EMP 테이블에서 “CLARK” 사원의 급여를 조회 합니다. 


 “CLARK” 사원의 sal 컬럼을 조회한다면 SQL은 SELECT sal FROM EMP WHERE ENAME = ‘CLARK’ 이러한 형태가 되고 인덱스를 경우하여 데이터를 조회한다고 가정을 했을 때 오라클은 원본 테이블 데이터가 있는 USERS 테이블스페이스table spaces의 EMP 테이블에 접근하는 것이 아니라 그림의 오른쪽 인덱스 영역에서 CLARK을 랜덤 액세스하여 찾고 그 ROWID 값을 이용하여 다시 원본테이블에 와서 sal 컬럼값을 추출 하는 것 입니다. 당연히 데이터 건수가 많은 경우에 효율적이고 건수가 얼마되지 않다면 비효율 적 일수도 있습니다. 여기서 건수가 많다 적다는 시스템 환경(CPU, MEMORY, DISK I/O 속도)에 따라 그 기준은 달라 집니다.


인덱스를 생성하는 기본형식은 아래와 같습니다.


[기본형식]

CREATE   [UNIQUE] INDEX   index_name 

ON   table_name (Column|Expr[,Column|Expr]...);



인덱스 종류


인덱스를 만드는형태에 따라 하나의 컬럼으로 인덱스를 만드는 단일인덱스, 여러개의 컬럼으로 인덱스를 만드는 복합 인덱스, 오름차순 또는 내림차순 인덱스, SQL함수나 표현식에 생성하는 함수기반 인덱스로 구분할 수 있습니다.


실제 인덱스가 내부적으로 어떻게 구성되어 지는지에 따라서 일반적인 오라클 인덱스인 균형잡힌 트리 형태의 B*Tree 인덱스, 비트를 이용하여 컬럼 값을 간결하게 저장하는 Bitmap 인덱스, 두 테이블 조인시 조인한 결과 칼럼에 대해 비트맵 인덱스를 생성하는 Bitmap Join 인덱스, 인덱스 컬럼의 값을 역으로 변경하여 B*Tree 인덱스를 구성한 역전환키 인덱스reverse key indexes 등이 있습니다.

인덱스가 꼭 필요한 이유


인덱스는 테이블 데이터에 액세스access 할 때마다 모든 행을 검색하지 않고도 데이터를 빠르게 찾는 데 사용됩니다. 기업에서 데이터베이스를 많은 자금을 들여 도입하는 이유중 하나는 빠른 검색 속도 입니다. 테이블에 데이터가 100건 있으나 1억건 있으나 조회 속도는 비슷해야 한다는 이야기죠. 


실무 현장에서 개발할 때 개발환경의 테이블에는 몇개의 행이 없지만 실 운영 상태가 되어 데이터 이행등을 한 후에는 어마어마한 데이터가 있을 수도 있다는 사실을 명심하고 SQL문을 작성할 때는 이점에 항상 신경을 쓰고 개발을 해야 합니다.

 

#인덱스란, #인덱스, #인덱스개요, #오라클인덱스, #ORACLE인덱스, #ORACLE, #오라클INDEX, #ORACLEINDEX​


(C#교육동영상)C# ADO.NET 실습 ODP.NET/ODAC 설치 오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원

  (C#교육동영상)C# ADO.NET 실습  ODP.NET/ODAC 설치  오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원 https://www.youtube.com/watch?v=qIPU85yAlzc&list=PLxU-i...