목차

    인덱스(Index) 란?

    인덱스는 데이터베이스 테이블에 대한 검색 성능의 속도를 높여주는 자료구조이다. 만약 인덱스를 타게 되면 먼저 인덱스에 저장 되어있는 데이터의 물리적 주소로 가서 데이터를 가져오는 식으로 동작하여 검색 속도의 향상을 가져올 수 있다.

    예시

    만약 다음과 같은 테이블이 있고 내가 이름(Data)가 SMITH라는 사람을 조회(Select) 하고자 한다면 full scan 작업이 필요하다.

    쿼리문

    더보기
    SELECT *
    FROM TABLE
    WHERE 1=1
    AND Data = 'SMITH'
    ;

    만약 인덱스 처리를 하면 다음과 같이 처리 할 수 있다. 마치 책에 있는 목차라고 생각하면 된다. 

    실제 DB 관련 작업을 할 때 대부분의 속도 저하는 바로 select문 특히 조건 검색 where절에서 발생하는데 가장 먼저 생각해 볼 수 있는 대안으로 Index를 생각할 수 있기도 하고, SQL 튜닝에서도 Index와 관련된 문제사항과 해결책이 많기 때문이다.

    인덱스(Index)를 사용하는 이유 : 조건 검색 Where 절의 효율성

    인덱스의 가장 큰 특징은 데이터들이 정렬이 되어있다는 점이다. 이 특징으로 조건 검색이라는 영역이 굉장히 장점이 된다. 테이블을 만들고 안에 데이터가 쌓이게 되면 테이블의 레코드는 내부적으로 순서가 없이 뒤죽박죽 저장된다. 하지만 인덱스 테이블은 데이터들이 정렬되어 있기 때문에 해당조건 where에 맞는 데이터들을 빠르게 찾아낼 수 있다. 위의 Index 테이블에서 SMITH 부분은 정렬이 되어있다.

    인덱스(Index)를 사용하는 이유 : 정렬 Order by 절의 효율성

    인덱스(Index)를 사용하면 Order by에 의한 Sort 과정을 피할 수 있다. Order by는 굉장히 부하가 많이 걸리는 작업이다. 정렬과 동시에 1차적으로 메모리에서 정렬이 이루어지고 메모리보다 큰 작업이 필요하다면 디스크 I/O도 추가적으로 발생된다. 하지만 인덱스를 사용하면 이러한 전반적인 자원의 소모를 하지 않아도 된다. 이미 정렬 되어 있기 때문에 가져오기만 하면 된다.

    인덱스(Index)를 사용하는 이유 : MIN ,MAX의 효율적인 처리가 가능하다.

    이것 또한 데이터가 정렬되어 있기에 얻을 수 있는 장점입니다. MIN값과 MAX값을 레코드의 시작값과 끝 값 한건씩만 가져오면 되기에 FULL TABLE SCAN 할 필요없다.

     

    인덱스의 단점

    인덱스가 주는 혜택이 있으면 그에 따른 부작용도 있습니다. 인덱스의 가장 큰 문제점은 정렬된 상태를 계속 유지 시켜줘야 한다는 점입니다. 그렇기에 레코드 내에 데이터값이 바뀌는 부분이라면 악영향을 미칩니다. INSERT, UPDATE, DELETE를 통해 데이터가 추가되거나 값이 바뀐다면 INDEX 테이블 내에 있는 값들을 다시 정렬을 해야겠죠. 그리고 INDEX 테이블, 원본 테이블 이렇게 두 군데에 데이터 수정 작업해줘야 한다는 단점도 있습니다.

     

    그리고 검색시에도 인덱스가 무조건 좋은 것이 아닙니다. 인덱스는 테이블의 전체 데이터 중에서 10~15% 이하의 데이터를 처리하는 경우에만 효율적이고 그 이상의 데이터를 처리할 땐 인덱스를 사용하지 않는 것이 더 낫습니다. 그리고 인덱스를 관리하기 위해서는 데이터베이스의 약 10%에 해당하는 저장공간이 추가로 필요합니다. 무턱대고 INDEX를 만들어서는 결코 안 될 말입니다. 

    인덱스(Index)의 관리

    앞서 설명했듯이 인덱스는 항상 최신의 데이터를 정렬된 상태로 유지해야 원하는 값을 빠르게 탐색할 수 있습니다. 그렇기 때문에 인덱스가 적용된 컬럼에 INSERT, UPDATE, DELETE가 수행된다면 계속 정렬을 해주어야 하고 그에 따른 부하가 발생합니다. 이런 부하를 최소화하기 위해 인덱스는 데이터 삭제라는 개념에서 인덱스를 사용하지 않는다 라는 작업으로 이를 대신합니다.

    • INSERT: 새로운 데이터에 대한 인덱스를 추가합니다.
    • DELETE: 삭제하는 데이터의 인덱스를 사용하지 않는다는 작업을 진행합니다.
    • UPDATE: 기존의 인덱스를 사용하지 않음 처리하고, 갱신된 데이터에 대해 인덱스를 추가합니다.

    인덱스 생성 전략

    생성된 인덱스를 가장 효율적으로 사용하려면 데이터의 분포도는 최대한으로 그리고 조건절에 호출 빈도는 자주 사용되는 컬럼을 인덱스로 생성하는 것이 좋습니다. 인덱스는 특정 컬럼을 기준으로 생성하고 기준이 된 컬럼으로 정렬된 Index 테이블이 생성됩니다. 이 기준 컬럼은 최대한 중복이 되지 않는 값이 좋습니다. 가장 최선은 PK로 인덱스를 거는것이겠죠. 중복된 값이 없는 인덱스 테이블이 최적의 효율을 발생시키겠고. 반대로 모든 값이 같은 컬럼이 인덱스 컬럼이 된다면 인덱스로써의 가치가 없다고 봐야 할 것입니다.

     

    1. 조건절에 자주 등장하는 컬럼

    2. 항상 = 으로 비교되는 컬럼

    3. 중복되는 데이터가 최소한인 컬럼 (분포도가 좋은) 컬럼

    4. ORDER BY 절에서 자주 사용되는 컬럼

    5. 조인 조건으로 자주 사용되는 컬럼

    B * Tree 인덱스

    인덱스에는 여러가지 유형이 있지만 그 중에서도 가장 많이 사용하는 인덱스의 구조는 밸런스드 트리 인덱스 구조입니다. 그리고 B TREE 인덱스 중에서도 가장 많이 사용하는것은 B*TREE 와 B+TREE 구조를 가장 많이 사용되는 인덱스의 구조입니다.

    B * Tree 인덱스는 대부분의 DBMS 그리고 오라클에서 특히 중점적으로 사용하고 있는 가장 보편적인 인덱스입니다. 구조는 위와 같이 Root(기준) / Branch(중간) / Leaf(말단) Node로 구성됩니다. 특정 컬럼에 인덱스를 생성하는 순간 컬럼의 값들을 정렬하는데, 정렬한 순서가 중간 쯤 되는 데이터를 뿌리에 해당하는 ROOT 블록으로 지정하고 ROOT 블록을 기준으로 가지가 되는 BRANCH블록을 정의하며 마지막으로 잎에 해당하는 LEAF 블록에 인덱스의 키가 되는 데이터와 데이터의 물리적 주소 정보인 ROWID를 저장합니다.

     

    인덱스 사용 예시

    인덱스 생성

    --문법
    CREATE INDEX [인덱스명] ON [테이블명](컬럼1, 컬럼2, 컬럼3.......)
    --예제
    CREATE INDEX EX_INDEX ON CUSTOMERS(NAME,ADDRESS); 
    
    --예제 컬럼 중복 X
    CREATE[UNIQUE] INDEX EX_INDEX ON CUSTOMERS(NAME,ADDRESS); 
    

    위와같이 쿼리문을 작성하면 INDEX를 생성할 수 있습니다. UNIQUE 키워드를 붙이면 컬럼값에 중복값을 허용하지 않는다는 뜻입니다.

    인덱스 조회

    SELECT * FROM USER_INDEXES WHERE TABLE_NAME = 'CUSTOMERS';
    

    인덱스를 생성하면 USER_INDEXES 시스템 뷰에서 조회할 수 있습니다. 방금 CUSTOMERS 테이블에 만들었던 EX_INDEX가 첫번째 ROW에 있군요.

     

    인덱스 삭제

    --문법
    DROP INDEX [인덱스 명]
    --예제
    DROP INDEX EX_INDEX;
    

    인덱스는 조회성능을 극대화하기 위해 만든 객체인데 너무 많이 만들면 insert, delete, update시에 부하가 발생해 전체적인 데이터베이스 성능을 저하합니다. 고로 안쓰는 인덱스는 삭제시키는것이 좋습니다.

     

    인덱스 리빌드

    인덱스를 리빌드하는 이유

    인덱스 파일은 생성 후 insert, update, delete등을 반복하다보면 성능이 저하됩니다. 생성된 인덱스는 트리구조를 가집니다. 삽입,수정,삭제등이 오랫동안 일어나다보면 트리의 한쪽이 무거워져 전체적으로 트리의 깊이가 깊어집니다. 이러한 현상으로 인해 인덱스의 검색속도가 떨어지므로 주기적으로 리빌딩하는 작업을 거치는것이 좋습니다.

     

    인덱스(Index)를 남발하지 말아야 하는 이유

    개발을 진행할때에 대개 개발서버와 운영서버를 나누어서 관리합니다. 대부분 개발서버에서 개발을 할때에는 적은량의 데이터를 가지고 로직검사를 하며 로직검사에 통과한 코드들이 운영서버에 업데이트가 되죠. 하지만 개발서버에는 잘 동작하던 로직들이 운영서버의 많은량의 데이터들을 처리하다보면 성능이슈가 많이 발생합니다. 그 성능이슈의 주요원인은 바로 데이터베이스에 있습니다. 데이터베이스 관리자는 성능문제가 발생하면 가장 빨리 생각하는 해결책이 인덱스 추가 생성입니다.

     

    문제를 쉽게 해결을 위해 쿼리 속도 문제가 날때마다 인덱스를 추가하는것은 바람직하지 못합니다. 성능 이슈가 나서 인덱스를 만들고 또 다른 SQL에서문에서 성능이슈가 발생하여 또 인덱스를 만들었다고 합시다. 이렇게 문제가 발생할때마다 인덱스를 생성하면서 인덱스가 계속 추가되면 생성된 인덱스를 참조하는 하나의 쿼리문을 빠르게는 만들 수 있지만 전체적인 데이터베이스의 성능 부하를 초래합니다. 그렇기에 인덱스를 생성하는것 보다는 SQL문을 좀 더 효율적으로 짜는 방향으로 나가야합니다. 인덱스생성은 꼭 마지막 수단으로 강구해야 할 문제입니다.

    정리

    인덱스(Index)는 데이터베이스 분야에 있어서 테이블에 대한 동작의 속도를 높여주는 자료 구조를 일컫는다. 인덱스는 테이블 내의 1개의 컬럼, 혹은 여러 개의 컬럼을 이용하여 생성될 수 있다. 고속의 검색 동작뿐만 아니라 레코드 접근과 관련 효율적인 순서 매김 동작에 대한 기초를 제공한다. 인덱스를 저장하는 데 필요한 디스크 공간은 보통 테이블을 저장하는 데 필요한 디스크 공간보다 작다. (왜냐하면 보통 인덱스는 키-필드만 갖고 있고, 테이블의 다른 세부 항목들은 갖고 있지 않기 때문이다.) 관계형 데이터베이스에서는 인덱스는 테이블 부분에 대한 하나의 사본이다.

    인덱스는 고유 제약 조건을 실현하기 위해서도 사용된다. 고유 인덱스는 중복된 항목이 등록되는 것을 금지하기 때문에 인덱스의 대상인 테이블에서 고유성이 보장된다.

    출처) 위키백과

    위의 내용을 정리하자면

    1. 테이블에 대한 검색의 속도를 높여주는 자료 구조입니다.
    2. 색인이고 메모리 영역의 일종의 목차를 생성하는 개념입니다.
    3. 따라서 이런 목차를 이용하여 검색 범위를 줄여 속도를 높일 수 있습니다.

    인덱스의 종류

    다음과 같이 정리할 수 있습니다!

    1. B(Balanced)-tree Index
    2. Bitmap Index
    3. IOT Index
    4. Clustered Index

    위와 같이 존재하며 주로 B-tree 구조로 사용된다고 합니다!


    왜 사용해야하나?

    위에서 말씀드렸듯이 검색의 속도를 높여주기 때문입니다. 근데 어떻게 검색의 속도를 높여주는것이며 어떻게 사용되는지 감이 안잡히기 때문에 이 내용에 대하여 설명해보겠습니다!

    예를 들어 오른쪽 테이블의 Physics값을 조회해본다고 가정해보겠습니다.
    해당 과정을 표현하면

    1. Select 절을 활용하여 조회
    2. 어느 위치에 데이터가 존재하는지 모르기 때문에 Table Full scan 진행

    이처럼 테이블의 전체 데이터를 조회하기 때문에 데이터의 수가 적은 테이블이면 영향이 덜하겠지만,

    만약 수십만개의 데이터가 들어있는 테이블의 데이터를 조회하는데 조회 기능이 자주 사용되는 서비스라면 성능이 굉장히 떨어지게 될것입니다!

    그렇기 때문에 왼쪽과 같이 인덱스를 따로 생성하여 해당 데이터만 빠르게 찾을 수 있게 됨으로써 다이나믹한 성능 향상을 기대할 수 있는 부분입니다!


    어떻게 동작하는것인가?

    위의 예시를 이어서 설명하겠습니다!

    1. 해당 테이블을 생성시 생성하고 싶은 인덱스 컬럼을 지정
    2. 생성 후 인덱스 조회 시, WHERE 절이 포함된 쿼리로 조회
    3. 인덱스로 저장된 Key-Value값을 참조해서 결과 출력

    위와 같이 진행되게 됩니다!

    다음과 같이 B-tree 알고리즘을 통하여 조회하게 되고, 리프노드로 도착하기 까지 자식 노드에 대한 포인터가 저장되어 있어 탐색에 있어서 한개의 경로만 조회하면 되기 때문에 조회에 있어서 굉장히 효율적인 알고리즘이라고 합니다!


    언제 사용해야하나?

    주로 검색 및 조회를 할때 큰 효율성을 낼 수 있다고 합니다!

    기본적으로 이진 트리를 사용하기 때문에 이미 정렬이 되어있는 상태에서 추가, 수정, 삭제가 자주 일어나게 되면 인덱스에서도 마찬가지로 해당 동작들이 수행되기 때문에 성능 저하를 초래할 수 있다고 합니다!

    예를 들어, 한 쇼핑몰에 여러가지 카테고리가 존재할때 해당 카테고리의 상품들을 조회할때 이러한 인덱스 기능을 잘 사용하게 된다면 큰 효율을 발휘하게 되지만, 인스타그램같은 소셜 서비스들은 끊임없이 게시글이 작성되고 수정, 삭제되기 때문에 오히려 인덱싱을 하게되면 엄청난 성능 저하가 되기 때문입니다!

    인덱스 선정 기준

    인덱스는 하나 혹은 여러 개의 컬럼에 대해 설정할 수 있습니다.
    단일 인덱스를 여러 개 생성할 수도, 여러 컬럼을 묶어 복합 인덱스를 설정할 수도 있습니다.

    그러나 무조건 많이 설정하는게 검색 속도 향상을 높여주지는 않습니다.
    인덱스는 데이터베이스 메모리를 사용하여 테이블 형태로 저장되므로 개수와 저장 공간은 비례합니다.
    따라서,

    • 조회시 자주 사용하고
    • 고유한 값 위주로

    인덱스를 설정하는게 좋습니다.

    그럼 어떤 컬럼에 인덱스를 설정하는게 좋을까?

    인덱스는 한 테이블당 보통 3~5개 정도가 적당합니다.
    물론 테이블의 목적 등에 따라 개수는 달라질 수 있습니다.

    인덱스는 컬럼을 정해서 설정하는 것이므로 후보 컬럼의 특징을 잘 파악해야 합니다.
    아래 4가지 기준을 사용하면 효율적으로 인덱스를 설정할 수 있습니다.

    • 카디널리티 (Cardinality)
    • 선택도 (Selectivity)
    • 활용도
    • 중복도

    카디널리티 (Cardinality)

    ✔️ 카디널리티가 높을 수록 인덱스 설정에 좋은 컬럼입니다.
    = 한 컬럼이 갖고 있는 값의 중복 정도가 낮을 수록 좋습니다.

    컬럼에 사용되는 값의 다양성 정도, 즉 중복 수치를 나타내는 지표입니다.
    후보 컬럼에 따라 상대적으로 중복 정도가 낮다, 혹은 높다로 표현됩니다.

    예를 들어, 10개 rows를 가지는 ‘학생’ 테이블에 ‘학번’과 ‘이름’ 컬럼이 있다고 해봅시다.

    • ‘학번’은 학생마다 부여 받으므로 10개 값 모두 고유합니다.
      • 중복 정도가 낮으므로 카디널리티가 낮습니다.
    • ‘이름’은 동명이인이 있을 수 있으니 1~10개 사이의 값을 가집니다.
      • 중복 정도가 ‘학번’에 비해 높으므로 카디널리티가 높다고 표현할 수 있습니다.

    면접 답변 : 고유한 값이 도출되는 것을 기반으로 인덱싱을 잡는 편 입니다. 예를들면 상품명이나 옵션보다는 상품번호, 주문번호, 배송번호 등 고유한 값에 인덱싱을 거는 편입니다.

    선택도 (Selectivity)

    ✔️ 선택도가 낮을 수록 인덱스 설정에 좋은 컬럼입니다.
    5~10% 정도가 적당합니다.

    데이터에서 특정 값을 얼마나 잘 선택할 수 있는지에 대한 지표입니다.
    선택도는 아래와 같이 계산합니다.

    = 컬럼의 특정 값의 row 수 / 테이블의 총 row 수 * 100
    = 컬럼의 값들의 평균 row 수 / 테이블의 총 row 수 * 100

    예를 들어, 10개 rows를 가지는 ‘학생’ 테이블에 ‘학번’, ‘이름’, ‘성별’ 컬럼이 있다고 해봅시다.
    학번은 고유하고, 이름은 2명씩 같고, 성별은 남녀 5:5 비율입니다.

    • ‘학번’의 선택도 = 1/10*100 = 10%
      • SELECT COUNT(1) FROM '학생' WHERE '학번' = 1; (모두 고유하므로 특정 값: 1)
    • ‘이름’의 선택도 = 2/10*100 = 20%
      • SELECT COUNT(1) FROM '학생' WHERE '이름' = "김철수"; (2명씩 같으므로 특정 값: 2)
    • ‘성별’의 선택도 = 5/10*100 = 50%
      • SELECT COUNT(1) FROM '학생' WHERE '성별' = F; (5명씩 같으므로 특정 값: 5)

    즉, 선택도는 특정 필드값을 지정했을 때 선택되는 레코드 수를 테이블 전체 레코드 수로 나눈 것입니다.

    즉 , 위의 예시에선 '학번' 정도를 index로 잡는 것이 좋다. 

    면접 답변 : 고유한 값이 도출되는 것을 기반으로 인덱싱을 잡는 편 입니다. 예를들면 상품명이나 옵션보다는 상품번호, 주문번호, 배송번호 등 고유한 값에 인덱싱을 거는 편입니다.

    활용도

    ✔️ 활용도가 높을 수록 인덱스 설정에 좋은 컬럼입니다.

    해당 컬럼이 실제 작업에서 얼마나 활용되는지에 대한 값입니다.
    수동 쿼리 조회, 로직과 서비스에서 쿼리를 날릴 때 WHERE 절에 자주 활용되는지를 판단하면 됩니다.

    면접 답변 : 저희 팀에서 자주 사용하는 기초 데이터 중 order_srl, buy_srl 같은 활용도가 높은 컬럼을 인덱싱하는 편 입니다.

    중복도

    ✔️ 중복도가 없을 수록 인덱스 설정에 좋은 컬럼입니다.

    중복 인덱스 여부에 대한 값입니다.

    인덱스 성능에 대한 고려 없이 마구잡이로 설정하거나,
    다른 부서 다른 작업자의 분리된 요청으로
    같은 컬럼에 대해 인덱스가 중복으로 생성된 경우를 볼 수 있습니다.

    인덱스도 속성을 가집니다.
    인덱스는 테이블 형태로 생성되므로, 속성을 컬럼으로 관리합니다.

    면접 답변 : 타팀에서 같은 테이블을 사용할 때 이미 인덱싱 처리되어 있는 것을 확인하고 인덱싱 신청을 하는 편 입니다.

    기준정도

    기준 정도
    카디널리티 (Cardinality) 높을 수록 적합
    선택도 (Selectivity) 낮을 수록 적합 (5~10% 적정)
    활용도 높을 수록 적합
    중복도 없을 수록 적합

     


    참고

    https://coding-factory.tistory.com/419

     

    [Oracle] 오라클 인덱스(Index) 사용법 총정리(생성, 조회, 삭제, 리빌드)

    인덱스(Index)란? 인덱스는 데이터베이스 테이블에 있는 데이터를 빨리 찾기 위한 용도의 데이터베이스 객체이며 일종의 색인기술입니다. 테이블에 index를 생성하게 되면 index Table을 생성해 관리

    coding-factory.tistory.com

     

     

    'Back-end > DB' 카테고리의 다른 글

    [DB] 결합 인덱싱  (0) 2022.05.14
    [DB] Dababase Sharding 이란?  (0) 2022.05.05
    인덱스 란? ***  (0) 2022.02.18

    + Recent posts