데이터베이스의 index?


Index는 책의 목차, 색인과 같은 역할을 담당하는 데이터베이스 객체로써 테이블과 독립적으로 존재합니다. 하지만 테이블에 의존적이기에 해당 테이블이 삭제될 경우 같이 제거되게 됩니다.

 

존재하는 칼럼의 값과 해당 레코드가 저장된 주소를 키와 값의 구조로 묶어 저장하고, 정렬된 상태를 유지하기에 저장, 수정, 삭제 기능들의 성능을 희생하고 빠른 조회를 제공하는 것이 Index의 사용 목적입니다.

 

 

 

기본 제공되는 Index?

기본적으로 제공되는 Index는 PK index 입니다. InnoDB는 설계상 이유 때문에 모든 테이블에 PK가 필요한데요. 개발자가 테이블에 PK를 작성하지 않는다면, 암시적으로 PK를 생성하여 레코드를 탐색하고 인덱스를 생성하는데 사용되게 됩니다.

 

 

 

 

Primary Key vs Secondary Key

  • Primary Key : 테이블마다 기본 키 제약 조건을 통해 만들어지는 하나의 고유한 Key를 의미하고, Null 값과 중복 값을 허용하지 않으며, 앞서 이야기한 것처럼 자동으로 인덱스를 생성하여 데이터에 대한 빠른 접근을 지원합니다.
  • Secondary Key : 각 레코드에 대한 고유한 값을 제공하는 Key를 의미하는데, Null을 허용하며, 레코드를 식별하는데 사용할 수 있고 Index로 활용할 수 있습니다. 하나의 테이블에 여러 Key가 존재할 수 있습니다.

 

 

 

Unique Index를 사용하는 이유?

Index에도 Unique Index와 Non-Unique Index가 존재하는데요. 간단하게 Unique Index를 알아봄으로써 어떠한 차이를 가지는지 확인해보겠습니다.

  • Unique Index : 하나의 Key만 존재함을 나타냅니다. 이는 Index에 대해 동등 조건을 사용하는 쿼리에서 DB의 쿼리를 실행하고 최적화하는 옵티마이저에게 하나의 Index를 찾았을 때 더 이상 스캔하지 않아도 된다는 의미를 제공하게 되며, 이를 통해 쿼리 최적화를 수행하게 되는데요. 그렇기에 사용 가능한 모든 경우에서는 Unique Index를 사용하는 것이 권장되게 됩니다.

    추가적으로 고유한 인덱스를 사용하는 것은 해당 레코드의 데이터 무결성을 보장하게 됩니다.

 

 

index의 장점?

  • 조회(SELECT) 쿼리의 성능을 향상시킵니다. 여러 서비스에선 데이터를 조회하여 사용자에게 제공하는 것이 다른 쿼리보다 많은 비중을 차지하기 때문에 도입하는 경우도 있습니다..

  • 고유한 index 형식을 사용한다면 이는 행에 대해서도 중복 없이 구성하는 것을 보장합니다.

  • 매번 테이블을 스캔한 후 행을 정렬하는 절차를 생략하게 합니다. 미리 정렬된 목록을 제공함으로써 매 쿼리마다 정렬을 하지 않아도 빠르게 데이터를 검색할 수 있도록 지원하게 됩니다.

    DB는 기본적으로 모든 행을 스캔하고 정렬한 뒤 일치하는 행을 필터링하여 결과를 반환합니다.

 

 

index의 단점?

  • 데이터의 수정(insert, update, delete)이 발생할 때마다 연관 index도 업데이트해야 합니다. 즉 다른 쿼리의 성능이 떨어지게 되는 문제점이 있습니다. update의 경우 where 조건에 index를 사용하고 있다면 해당 칼럼을 찾아 변경하는 성능을 높일 수 있습니다. (index update는 동일하다.)
  • Index는 DB 내에서 별도의 저장 공간을 차지합니다.
  • Index를 유지하는 비용이 발생합니다. 대표적으로 데이터 수정 , 삭제, 추가 등의 경우 Index가 업데이트되다가 깨지는 경우가 발생하게 되는데 이때 복구, 정상적인 Index로의 우회 등 추가적인 처리가 필요합니다.

 

 

Index Corruption?

Corrupt Index는 DDL, DML(insert, update, delete) 쿼리를 수행한 뒤 정렬하는 도중이나, Slow Query에 의한 비정상적인 종료에 의해 발생할 수 있습니다. 하지만 확실하게 손상되었는지 확인할 수 없기 때문에, 이를 파악하기 위해서는 테스트를 통해 실행시간과 결과를 관찰하여야 합니다.

 

 

 

index를 사용하여야 하는 시점?

테이블에 인덱스를 추가하는 것은 저장 속도를 어디까지 희생하고, 읽기 속도를 얼마나 더 빠르게 만들어야 하는지의 여부에 따라 결정되어야 합니다.

 

인덱스를 추가하거나 제거할 때마다 성능 테스트를 수행하여 어떤 영향이 미치는지 실질적인 수치를 파악하여야 하고, 

이는 많은 검색 쿼리에서 빈번하게 키로 사용되는 컬럼을 인덱스로 사용한다는 것이 기본 전제가 되는데요, 이를 정량화(수치로 만들어서)하여 판단해야 한는 것이 좋습니다.

 

 

 

index의 알고리즘?

간단하게 Index 알고리즘의 종류와 개념만 작성하였습니다.

  • B-Tree Index : balanced Tree를 사용하는 방식을 의미하며, 일반적으로 사용되는 유형입니다. 칼럼의 값을 변형하지 않고, 원래의 값만을 이용해 Indexing 하는 특성을 가지게 됩니다.

    여러 형태의 변형된 알고리즘을 가집니다. B+-Tree, B-Tree 등*

  • Hash Index : 컬럼의 값을 Hash 값으로 계산하여 Indexing 하는 방식입니다. 매우 빠른 검색을 지원하나 일부 값을 통해 값을 찾는 Pattern matching을 지원하지 못합니다. 주로 메모리 기반의 DB에서 사용됩니다. 

  • Fractal-Tree Index : B-Tree 방식의 단점을 보완하기 위해 고안된 방식입니다. 값을 변경하지 않고 인덱싱 하는 것은 동일하나 데이터가 저장되거나 삭제될 때 발생하는 비용 (Disk I/O)을 줄이도록 설계된 것이 특징입니다. 각 내부 노드에 버퍼를 포함함으로써 데이터를 임시로 저장하고 버퍼가 가득 채워졌을 때 Flush 하게 됨으로 I/O 작업 단위를 크게 만들어서 유지하게 됩니다.

  • R-Tree Index : 2차원 데이터를 Indexing 하고 검색하는 목적을 지니는 방식입니다. 주로 공간 개념 값을 사용하는 GPS나 GIS 서비스에서 사용하게 됩니다.

  • Full Text Search Index : 문서의 내용 전체를 Indexing 하여 특정 키워드가 포함된 문서를 분석, 검색하는 방식에서는 B-Tree 형식을 사용할 수 없기에 사용되는 방식입니다. 크게 Stopword 방식과 N-Gram 방식으로 이야기할 수 있습니다.

 

 

자료 출처


 

 

 

Bedocs Study DbUnit 발표 후기


발표 자료

 

발표하며 느낀 것들

금주 목요일에는 저에게 생소했던 라이브러리인 DbUnit에 대해 학습하고, 정리된 내용과 예제 프로젝트를 이용해 발표하는 시간을 가지게 되었습니다.

 

새로운 개념과 라이브러리를 학습하는 것은 즐겁지만, 어려운 경우도 종종 있었는데, 특히 이번 주제인 DbUnit은 공개된 문서의 초기 설정 등이나 레퍼런스가 부족하여 더 어려움이 있었던 것 같습니다.

 

참여하시는 분들이 대부분 직장인이셔서 야근 등의 문제로 (발표) 일정이 1주일 밀렸었는데, 그 덕에 준비를 좀 더 할 수 있었고 실수(거의?) 없이 라이브로 환경 설정부터 테스트 코드 작성까지 할 수 있었던 것 같습니다.

 

 

뿌듯한 시간이었고 다들 좋은 반응들을 해주셔서 정말 감사했었습니다. 


 

 

 

Go Hello World!


지난 화요일 저녁에 여유가 생겨서 요즘 인프라, 컨테이너 관련 오픈소스나 MSA에서 자주 사용되는 Go 언어를 찾아보고 간단하게 코딩도 해보았습니다.

 

 

학습 중인 자료 (무료 E-Book)

 

중괄호 위치 등의 Coding Convention을 제한하고 메서드 명명 규칙을 기능으로써(?) 제공하는 부분이 정말 재미있었는데요. 이미 기존에 학습하시고 사용하시는 분들이라면 김 빠지실 수 있겠지만, 이런 부분이었습니다.

// private method, 외부 접근 불가능
func sayBye() {
  fmt.Println("bye")
}

// public method, 외부 접근 가능
func SayHello() {
  fmt.Println("hello")
}

소한 즐거움..?

 

현재 자바를 이용해 프로젝트를 하며 드는 생각은 문법이 읽기 좋지만, 너무 많은 코드를 작성하게 된다라는 점이 있는데요. Go는 간단한 문법을 내세우는 언어답게 간결하면서도 제가 좋아하는 정적, 강타입도 지키는 언어이기에 정말 마음에 들었습니다. (변수 타입은 컴파일 시점에서 결정되지만요.)

// Java : 1
public static void main(String[] args) {

        int a = 0, i;
        for (i = 0; i < 10; i++) {
            a += i;
        }

        System.out.println(a);
}

// Java : 2
public static void main(String[] args) {

        int a = 0, i = 0;
        while (i != 10) {
            a += i;
            i++;
        }

        System.out.println(a);
}

// Go
func main() {
        sum, i := 0, 0

    for i < 10; {
        sum += i
        i++ 
    }
    fmt.Println(sum)
}

이런 예제에서는 간결함을 크게 느낄 수는 없겠지만요.

 

물론 없는 문법도 많고.. (예외 처리라던지?) 핵심 라이브러리도 부족하다고 하지만, 모든 언어가 모든 상황에서 좋은 경우는 없기 때문에 (그렇게 믿고 있습니다.) 충분히 감내할 수 있는 부분이라고 생각합니다.

 

여유가 생길 때마다 새로운 기술과 언어를 꾸준하게 공부할 생각인데 이러한 마음가짐이 계속 갔으면 좋겠습니다. ㅎㅎ

 

 

이번 한 주 다들 노고가 많으셨고요. 주말에 푹 쉬시고 다음 주도 힘차게 나아가 봅시다! 파이팅!

 

 

+ Recent posts