데이터베이스 비교 방법

먼저, 목표가 명확해야한다.

 

대부분의 목표는 성능일 것. 데이터베이스에 가하는 워크로드를 파악하고, 데이터베이스 벤더에서 제공하는 부하 테스트 툴을 통해 성능 테스트를 해보는 게 좋다.

 

워크로드에는 읽기/쓰기 쿼리 비율, 예상 트래픽, 쿼리 유형 등을 결정해서 정하면 됨.

 

데이터베이스 용도

데이터베이스는 다양한 용도가 있다:

  • 온라인 트랜잭션 처리 (OLTP) 데이터베이스
  • 온라인 분석 처리 (OLAP) 데이터베이스
  • 장기 보관을 위한 콜드 스토로지
  • NoSQL 데이터베이스 (e.g 빅데이터 처리를 위해서, 수평적 확장성과 높은 읽기/쓰기 성능을 위해서, 유연한 스키마와 확장성을 위해서 등)
  • 빠른 성능을 위한 인메모리 데이터베이스
  • 시간에 따른 데이터 변화를 기록하고 싶은 시계열 데이터베이스

 

DBMS 공통된 구조

  • 트랜스 포트 서브 시스템: 클라이언트 요청을 쿼리 프로세서에 전달하는데 사용됨. 그리고 요청은 쿼리 형태로 포함됨.
  • 쿼리 프로세서 시스템: 쿼리를 분석하고 가장 효율적인 쿼리 실행 계획을 결정하는 역할을 함
  • 실행 엔진: 데이터베이스 시스템에 따라서 원격 실행이나 로컬 실행을 함. 로컬 실행을 할 경우에는 스토로지 엔진이 데이터를 가져오고 쓰는 역할을 한다. 원격 실행을 하는 경우에는 다른 시스템에 명령을 내리고 결과를 조홥하는 역할을 한다.
  • 스토로지 엔진:
    • 트랜잭션 매니저: 트랜잭션을 스케줄링하고 데이터 일관성을 보장하는 역할을 한다.
    • 잠금 매니저: 트랜잭션에서 접근하는 데이터베이스 객체에 잠금을 걸어서 동시성을 제어하는 역할을 한다.
    • 엑세스 메소드: 디스크에 저장된 데이터를 특정 자료구조 (B-Tree, LSM Tree 등) 으로 가져오고, 디스크로 쓰는 역할을 한다.
    • 버퍼 매니저: 데이터 페이지를 메모리에 캐시하는 역할을 한다.
    • 복구 매니저: 로그를 쓰고, 복구하는 역할을 담당한다.

 

인메모리 DBMS vs 디스크 DBMS

인메모리 DBMS 는 데이터를 메모리에만 저장하고, 디스크에는 로그와 복구를 위한 스냅샷 데이터만 저장한다.

 

반면 디스크 DBMS 는 데이터를 디스크에 저장하고, 메모리로 일부 데이터를 가져와서 클라이언트에게 전달한다.

 

Q) 인메모리 DBMS 를 왜 사용하는가?

  • 빠른 성능을 위해서, 디스크 접근 보다는 메모리 접근이 더 빠르니까.
  • 메모리 접근 및 관리가 디스크 접근 및 관리보다 훨씬 간단하다. 메모리 관리는 할당과 해제 위주인 반면에, 디스크는 디스크 데이터 접근과, 디스크에 저장할 때 직렬화 과정이 필요하고, 디스크 데이터를 메모리에 가져올 때 메모리 해제와, 메모리 단편화 현상 같은 것도 고려해야한다.

 

Q) 그럼 디스크 DBMS 는 왜 쓰는가?

 

메모리가 디스크보다 훨씬 비싸니까. SSD 가 비싸더라도 메모리 보다는 훨씬 싸다.

 

 

Q) 인메모리 DBMS 는 휘발되는 문제도 있는거 아닌가요?

 

비휘발성 메모리도 있다.

 

휘발성 메모리라도 무정전 전원 장치와 베티러를 이용하는 RAM 을 쓰면 되기도 한다.

 

 

Q) 디스크 DBMS 도 데이터를 메모리에 모두 올려서 쓸 수 있다면 인메모리 DBMS 와 성능 차이는 나지 않겠네요?

 

아니다.

 

인메모리 DBMS 가 성능 적으로 유리하다.

  • 직렬화 측면
  • 메모리에 최적화된 자료구조와 알고리즘 때문에. (디스크 DBMS 는 디스크 저장/조회에 최적화된 자료구조와 알고리즘을 사용할 것.)

 

디스크 DBMS 는 디스크 엑세스, 즉 디스크 I/O 를 효율적으로 하기 위한 자료구조와 알고리즘을 사용한다.

  • B-Tree, B+Tree:
    • B-Tree 의 경우 하나의 노드에 여러 연속된 데이터를 모두 저장해서 한번에 디스크에 저장할 수 있는 구조이며, 저장, 검색, 업데이트 등의 시간 복잡도도 준수하다.
    • B+Tree 의 경우 리프 노드가 포인터로 논리적으로 연결되어 있어서, 범위 검색을 하는 경우에 선형 I/O 를 하도록 최적화 하는게 가능함.
  • LSM Tree:
    • 쓰기 버퍼링으로 한번에 디스크로 저장하며, 이떄 Linear I/O 를 사용한다.
    • 디스크에 저장된 이후 각 데이터 파일을 Merge Compaction 과정에서도 Linear I/O 를 사용함.

 

메모리 DBMS 는 해시 테이블, Red Black Tree 등 다양한 자료구조를 쓸 수 있다.

  • 메모리 DBMS 는 포인터를 이용해서 메모리 참조를 적극적으로 이용할 수 있는 반면에, 디스크 DBMS 는 포인터를 이용하면 랜덤 디스크 I/O 가 발생하니까, 이걸 적극적으로 이용하지 못함.

 

 

데이터 엑세스 패턴의 중요성: 칼럼형 DBMS vs 로우형 DBMS vs 와이드 칼럼 스토어

로우형 DBMS:

  • 데이터를 로우(Row) 단위로 저장한다. 학생 데이터라고 한다면 하나의 로우는 하나의 학생을 의미하고, 이 묶음으로 데이터를 저장하는 것을 의마한다.
  • 데이터 엑세스 패턴이 특정 학생의 모든 데이터에 접근하거나, 일부 학생의 범위에 접근하는 경우가 많을 경우에 이 DBMS 가 유리하다.
  • 반대로 특정 학생의 칼럼에만 접근하는 경우가 많다면 유리하지 않음.

 

칼럼형 DBMS:

  • 데이터를 칼럼 단위로 저장한다. 그래서 학생 데이터라고 한다면, 학생 이름 따로, 학생 번호 따로 이렇게 저장하는 것을 의미한다.
  • 집계나 평균을 내는 통계와 같은 작업을 할 때, 데이터 분석을 위해 일부 중요한 칼럼만을 읽을 때 해당 데이터베이스가 유리하다. 아니면 많은 데이터를 읽는 경우가 많거나.
  • 같은 칼럼끼리 저장하므로, 데이터 저장을 압축해서 효율적으로 할 수 있다.
  • CPU 벡터 연산을 적극적으로 활용해서 한 번에 많은 데이터를 처리할 수 있다.

 

와이드 칼럼 스토어:

  • 칼럼 패밀리별로 데이터를 나눠서 저장하지만, 데이터를 특정 시점 별로 분리해서 저장한다. 이를 다차원 맵으로 표현한다고도 함.
  • 예시는 아래 표와 같다:
    • 칼럼 패밀리, 로우 키, 칼럼 수식자, 타임 스탬프, 그리고 값 이렇게 들어가있다.
    • 칼럼 패밀리: UserProfile, 로우 키: UserId, 칼럼 수식자: Name, Friend, Post 등, Timestamp: 20230401 등
  • 데이터 접근 방법: 칼럼 패밀리로 먼저 접근 -> Row Key 사용 -> 칼럼 수식자와 타임 스탬프 사용 (Optional)
Row Key Column(Key:Timestamp) Value
1 Name:20230401 Alice
1 Email:20230401 alice@example.com
1 Friends:UserID:2:20230401 True
1 Friends:UserID:3:20230401 True
1 Posts:PostID:1:20230401 Content of post 1
1 Posts:PostID:2:20230402 Content of post 2
2 Name:20230401 Bob
2 Email:20230401 bob@example.com
2 Friends:UserID:1:20230401 True
2 Friends:UserID:3:20230402 True
2 Friends:UserID:4:20230403 True
2 Posts:PostID:3:20230402 Content of post 3
... ... ...

 

데이터를 저장하는 방식: 데이터 파일과 인덱스 파일

 

데이터베이스에서 데이터를 저장하는 파일 유형은 크게 3가지이다.

  • Heap Organized Table:
    • 가장 기본적인 형태의 데이터 파일.
    • 삽입하는 순서에 따라 저장되는게 특징이다. 특정 순서 없이 넣는대로 저장된다.
    • 데이터는 차례대로 저장되니까, 데이터에 빠르게 접근하기 위해서는 인덱스가 필요하다. 인덱스에서는 해당 파일의 오프셋 값이 들어갈 것이고, 이걸 통해서 한번에 데이터 파일에서 조회할 수 있다.
  • Index Organized Table:
    • 테이블의 전체 데이터가 인덱스에 저장되는 구조이다. 기존 방식은 인덱스 조회 이후에 데이터 파일 조회가 이뤄졌는데, 이 방식은 인덱스만 조회하면 된다. 그래서 Primary Key 기반의 검색에는 엄청 빠르다.
    • 이 구조는 삽입과 갱신에 오버헤드가 크게 발생할 수 있다:
      • 삽입 오버헤드: 행이 삽입될 때 Primary Key 키에 맞게 정렬되도록 구성해야하므로, 삽입되는 행만 넣는게 아니라 다른 행들의 재배치가 필요할 수 있다.
      • 갱신 오버헤드: Primary Key 를 변경하는 경우에는 해당 위치에 다시 데이터를 기록해야하므로 다른 행들 위치도 변경해야한다. Primary Key 가 아닌 다른 데이터를 갱신하는 경우에, 기존에 차지하고 있는 데이터보다 사이즈가 커진다면 이 또한 다른 데이터를 밀어내고 기록해야한다.
  • Hash Organized Table:
    • 해시 함수를 사용해서 행의 위치를 결정하는 방식이다. 특정 키 값을 입력하면 빠르게 조회할 수 있다는게 특징임.
    • 주로 키-값 조회로 데이터에 엑세스 한다면 빠르지만, 범위 기반의 쿼리에는 약하다.

 

인덱스 파일은 데이터 파일에 있는 데이터를 쉽게 검색하기 위해 사용되는 파일이다.

 

인덱스 파일은 클러스터링 인덱스와 비클러스터링 인덱스 파일로 나뉜다.

  • 클러스터링 인덱스:
    • 테이블의 데이터를 기본 키 순서대로 물리적으로 정렬해서 기록되어있는 파일이다.
    • 인덱스 키 값은 정렬되고, 해당 키에 데이터 파일의 데이터도 포함된다.
  • 비클러스터링 인덱스:
    • 인덱스로 선언한 칼럼대로 정렬되어 있고, 테이블 레코드의 위치나 기본 키 값이 기록되어있는 파일이다.
    • 그러니까 인덱스 값으로 데이터 행을 가리키는 포인터가 있는 것.

 

Q) 왜 클러스터링 인덱스와 비클러스터링 인덱스로 나눠져있나요?

 

둘 다 인덱스이므로 데이터 파일 접근을 빠르게 하기 위해서 사용됨.

 

클러스터링 인덱스는 기본 키를 가지고 데이터 파일을 빠르게 조회할 수 있다. 범위 기반의 쿼리라도.

 

비클러스터링 인덱스는 테이블 내의 다른 키들을 가지고도 데이터 레코드에 빠르게 조회하도록 만들기 위해서 사용된다.

 

 

Q) 클러스터링 인덱스가 없고, 비클러스터링 인덱스만 있다면?

 

그러면 비클러스터링 인덱스에 레코드 파일의 위치 값이 들어가야하는데, 이 경우에 레코드 파일의 위치가 삭제되거나 변경되는 일만 생겨도 갱신의 부하가 많다.

 

그리고 비클러스터링 인덱스는 데이터가 물리적으로 연속된 곳에 저장되어 있지 않기 때문에 범위 기반의 검색을 할 경우 랜덤 디스크 I/O 가 많이 발생하게 된다.

 

 

Q) 클러스터링 인덱스 유형만 있다면?

 

인덱스 파일이 삭제되거나 갱신되거나 할 때마다 그와 연계된 오버헤드가 많이 발생한다.

 

 

Q) 클러스터링 인덱스는 인덱스에 데이터 파일을 같이 저장하는 거니까, 이걸 쓰는 경우에는 데이터 파일이 필요 없는가?

 

그렇다.

 

 

Q) 그럼 Heap Organzied Table 로 데이터를 저장하는 구조에서는 클러스터링 인덱스를 사용하지 않는건가?

 

그렇다. 여기서는 비클러스터링 인덱스만을 사용한다.

 

 

Q) 그럼 Index Organized Table (IOT) 에서는 클러스터링 인덱스를 이용하고 있는건가?

 

그렇다.

 

인덱스를 통한 직접 참조와 간접 참조 비교

테이블 데이터 레코드에 엑세스 할 때 기본 키를 통해 참조하는 방식과 데이터 파일의 파일 오프셋을 가지고 직접 참조하는 방식을 비교해보자:

  • 기본 키를 통한 참조 방식:
    • 데이터 접근 방식은 2번의 룩업을 통해서 이뤄진다: 비클러스터링 인덱스 -> 클러스터링 인덱스 -> 데이터 접근
    • 대신에 데이터 파일의 데이터가 변경되더라도, 클러스터링 인덱스에서만 데이터가 변경되면 된다.
  • 데이터에 직접 참조:
    • 데이터 파일의 위치가 바뀌면 인덱스마다 갱신을 해줘야한다.
    • 인덱스를 여러개 쓰는 경우라면, 갱신 비용이 점점 커진다.

 

스토로지 엔진의 특성: 데이터베이스 자료구조의 공통점인 버퍼링, 불변성, 순서화

데이터베이스 자료구조에서 사용되는 특성들은 다음과 같다:

  • 버퍼링:
    • 디스크에 쓰기 전에 최대한 메모리에서 모아서 한번에 디스크에 쓰는 방식을 말함.
  • 불변성:
    • 한번 쓴 데이터는 변경하지 못하도록 하는 것. 이는 데이터를 오로지 append-only 로만 기록할 수 있음을 말한다.
    • COW (copy-on-write) 방식으로 데이터를 변경하는 방법도 있다.
  • 순서화:
    • 데이터를 특정 키 순서대로 연속적으로 디스크에 기록하는 것. 그래서 범위 검색에 강하게 만드는 방법이다.
    • 들어온 순서대로 데이터를 기록하는 방법도 있긴하다. 이 방법은 특히 쓰기에 강함. 비트캐스크 (Bitcask) 가 이런 방식으로 동작한다.

 

References

+ Recent posts