DB System Concepts 7th

[DB] 13-6. Column-Oriented Storage

patrick-star 2023. 8. 6. 17:23
728x90

전통적으로 DB는 하나의 record 안에 모든 속성에 대한 값을 저장한 튜플을 저장하고 그 튜플은 지금까지 봐왔던 file에 저장된다. 이러한 저장 방식을 row-oriented storage라고 한다.

반면, Column-Oriented Storage에서는 relation의 각 속성(attribute)속성의 값과 함께 별도로 저장된다.
이때, 연속된 튜플의 해당 속성 값들은 파일 내에서 연속된 위치에 저장된다.

  • 그림 : instructor relation이 column-oriented storage 방식으로 어떻게 저장되는지 보여준다.

Column-Oriented Storage의 가장 간단한 형태에서 각각의 속성(attribute)은 별도의 파일에 저장된다. 게다가, 각각의 파일은 크기를 줄이기 위해서 압축되어 있다. (이에 대한 자세한 내용은 뒤에서 다룰 예정)

만약에 쿼리가 테이블의 i번째 row의 전체 내용에 접근해야 한다면, 각 컬럼의 i번째 위치에 있는 값을 불러와서 row를 재조립하는데 사용된다. 때문에 여러 개의 row로 부터 여러 개의 attribute를 가져오는 쿼리에는 적합하지 않다.

하지만, Column-Oriented Storage 방식은 데이터 분석 쿼리에 잘 맞는다. relation의 많은 개수의 row를 처리하지만 비교적 적은 개수의 attribute를 처리하는 경우에 적합하다. 이유는 다음과 같다.

  • Reduced I/O
    쿼리가 적은 개수의 attribute에만 접근해야 한다면 나머지 attribute들을 굳이 disk에서 memory로 가져올 필요가 없다.
    하지만, Row-Oriented Storage방식이었다면 필요없는 attribute들까지 가져와야 했을 것이다.
    이와 같이 I/O 횟수를 감소시킴으로써 쿼리를 실행하는 비용을 줄일 수 있게 되었다.

  • Improved CPU Cache Performance
    질의 처리기(query processor)가 특정 속성의 내용을 읽어올 때
    최신 CPU 구조를 사용해서 캐시 라인(cache line)이라고 하는 연속된 바이트를 memory에서 CPU 캐시로 읽어온다.

만약에 이후에 동일한 바이트에 접근한다면, 당연이 main memory에서 바이트를 가져오는 것 보다 CPU 캐시에서 바이트를 가져오는 것이 더 빠르다.
물론, query에서 필요하지 않은 속성값을 불러와서 캐시에 저장한다면 저장 공간을 낭비하게 되겠지만
column-oriented 방식을 사용한다면 인접한 바이트가 같은 열에 존재하고 데이터 분석 질의(data analysis query)는 일반적으로 이러한 모든 값에 연속적으로 접근하기 때문에 저장 공간 낭비에 대해서 고민하지 않아도 된다.

  • Vector Processing
    CPU 구조가 벡터 처리(Vector Processing)를 지원한다는 것은 배열의 여러 요소CPU 연산을 병렬적으로 실행할 수 있다는 걸 의미한다. 열 단위로 데이터를 저장하면 속성과 상수를 비교하는 것과 같은 연산을 벡터처리할 수 있게 되는데 이는 relation에 선택 조건을 적용하는 데 중요하다. 또한 벡터 처리는 한 번에 하나의 값을 집계하는 대신에 병렬로 여러 값의 집계(aggregation)를 계산하는데 사용되기도 한다.

이러한 이점 때문에 데이터 분석 질의를 처리하는 date-warehousing 응용 프로그램에 column-oriented storage를 많이 사용한다.
column-oriented storage의 성능을 향상시키려면 인덱싱 및 query 처리 기술을 신중하게 설계해야 하는데 이에 대한 내용은 14.9, 24.3에서 자세하게 살펴본다.

column-oriented storage를 사용하는 DB를 열 저장소(column store)라고 하고
row-oriented storage를 사용하는 DB를 행 저장소(row store)라고 한다.

방금까지 column-oriented storage의 장점을 살펴봤다면 이번에는 단점을 살펴보자. 이 단점때문에 트랜잭션 처리에 적합하지 않다.

  • Cost of tuple reconstruction

개별적인 column을 가지고 튜플을 재구성하는 건 비용이 많이 든다는 건 앞서 언급했다.
이러한 튜플의 재구성은 트랜잭션 처리 응용 프로그램에서 많이 사용한다.
반면 데이터 분석 응용 프로그램은 보통 데이터 웨어하우스의 팩트 테이블(fact table)에 저장된 속성 중 일부만 출력한다.

  • Cost of tuple deletion and update

압축된 형식에서 단일 튜플을 삭제 또는 갱신하려면 하나의 단위로 압축된 튜플의 전체 순서(sequence)를 다시 써야 한다.
트랜잭션 처리 응용 프로그램에서 튜플의 삭제와 갱신은 흔하게 발생한다.
때문에 column-oriented storage는 하나의 단위로 많은 튜플이 압축되어 있다면 삭제 및 갱신과 같은 연산을 수행하는데 큰 비용이 발생한다.

반대로 데이터 웨어하우스 시스템은 튜플에 대한 갱신 대신에 새로운 튜플의 삽입 & 이전 튜플의 대량 삭제를 지원한다.
여기서 삽입은 relation의 끝에 새로운 튜플을 추가하는 형식으로 실행된다.

따라서, 속성값으로 이뤄진 커다란 sequence를 하나의 단위로 함께 저장하고 압축할 수 있으므로 작은 sequence보다 더 효율적으로 압축할 수 있다.

  • Cost of decompression

압축된 형식에서 데이터를 읽어올 때 압축 해제(decompression)를 해야 하는데 가장 간단한 압축 형식에서는 파일의 처음부터 모든 데이터를 읽어야 한다.

트랜잭션 처리 query의 경우 일반적으로 몇 개의 레코드를 읽어오는 동작이 필요하다.
이렇게 되면 몇 개의 관련 record에 접근하기 위해 관련 없는 많은 record들의 압축을 해제해야 하기 때문에 순차 접근의 비용이 매우 커진다.

데이터 분석 질의(data analysis query)는 연속적으로 많은 레코드에 접근하는 경향을 갖고 있기 때문에 일반적으로 압축 해제에 소요되는 시간은 크지 않다.
하지만, 데이터 분석 질의(data analysis query)
select 조건에 맞지 않는 레코드에 접근할 필요가 없고 디스크 I/O를 줄이기 위해 조건에 맞지 않는 레코드의 속성을 건너뛰어야 한다.

이렇게 조건에 맞지 않는 레코드의 속성을 건너뛰기 위해 column-oriented storage의 압축 형식을 사용하면 파일의 이전 부분을 건너 뛰고 파일의 임의 지점에서 압축 해제를 시작할 수 있다.

ex) 10,000개의 값마다 새롭게 압축한다고 하자

만약 파일의 i번째 값을 알고 싶다면 10,000개의 값을 갖는 그룹마다 시작 위치를 찾고 ⌊i∕10000⌋번째 그룹의 시작 부분으로 이동하면 된다. 그런 다음에 그 위치에서부터 압축 해제를 시작해서 i번째 값에 쉽게 접근할 수 있다.

ex1) i = 5283

그러면 ⌊i∕10000⌋ = ⌊5283∕10000⌋ = 0번째 그룹의 시작부분으로 이동해서 해당 그룹부터 압축해제를 시작해서 5283번째 값을 찾아나가면 된다.

ex2) i = 211436

그러면 ⌊i∕10000⌋ = ⌊211436∕10000⌋ = 21번째 그룹의 시작부분으로 이동해서 해당 그룹부터 압축해제를 시작해서 211436번째 값을 찾아나가면 된다.

column-oriented storage를 사용하는 대표적인 방식으로 빅데이터 처리 응용 프로그램에서 사용하는 ORC와 Parquet가 있다.
(자세한 내용은 책 p.560 ~ 562 / pdf p.642 ~ 644)