DB Review (3)

이미 DDIA책, 수업 등의 경험으로 DB에 대한 지식을 어느정도 갖췄지만, 기본적인 거를 정리할 겸 블로그를 사용하고자 한다. 큰 컨셉들을 정리하고 생각해보는 시간을 갖출 것이다. 이 내용은 추후 더 정리하거나 추가될 수도 있다.

NoSQL

NoSQL이란 Relational Model (관계형 모델)을 지양하는 저장소를 의미한다. 그렇다면 NoSQL은 일반 관계형 모델과 어떻게 다를까? NoSQL은 크게 Document Model과 Graph Model로 나눌 수 있다.

  • Document Model
    Document Model의 경우 대부분의 데이터가 XML이나 JSON형태로 저장된다. NoSQL의 경우에는 write가 빠르게 되어야 할때 도움이 되며, schema-on-read를 지원하여 schema에 대한 pressure를 줄여주고 자유롭게 document를 작성하게 함. 또한 one-to-many에 매우 유용함. 그러나 many-to-one이나 many-to-many 에는 유용하지않음. 또한 storage locality에 의하여 전체 document 내 내용을 자주 불러와야할때 도움이 됨.
  • Graph Model Graph Model은 many-to-many에 탁월함. 그래프 모델은 vertices와 edges로 나뉘고, vertices는 사람, 이벤트, 장소 등을 뜻하고 edges는 관계를 의미함. Property Graph (Neo4j, Titan)과 Triple-Stores (Datomoic) 모델이 있음.

Query Language

Imperative Query Langauge은 명령형 프로그래밍으로 대부분의 프로그래밍 언어에 쓰인다. 그러나 Query Language로는 CODASYL정도에 쓰인다. Declartive Query Language는 선언형 프로그래밍으로 우리가 쓰는 SQL이 이것에 속하고, Select등으로 Pattern을 정해주면 Query Optimzer가 알아서 Optimize해준다. 이 중간에 있는 것이 MapReduce Query Language인데, Hadoop등에서 쓰인다. Map, Reduce의 두가지로 나뉘고, Map은 matching하는 데이터를 찾아 key-value pair를 내보내고, reduce는 이를 집계하여 값을 내보낸다. Map과 Reduce는 Side Effect가 있으면 안된다.

Index

Index에 대해서는 할말이 많지만..! 핵심만 정리해보겠다. Index는 읽기를 빠르게 하기 위해 만들어둔 것으로, 때문에 쓰기 속도는 살짝 느려진다. 따라서 필요한 부분에만 Index를 만드는게 중요하다. DB마다 색인을 위해 다른 저장소 엔진을 선택하는데, 크게 log-structured engine과 page-oriented engine이 있다.

Log-Structured Engine

기본적인 것으론 Hash-Indexes가 있다. Bitcask같은 곳에서 쓰이는데, 인메모리에 hash map을 놓음으로서 빠르게 읽고 쓸 수 있다. 이런 경우는 key의 양이 작고, key가 자주 업데이트 된다면 (video 주소와 얼마나 자주 플레이 되는지) key value로 store할 수 있다. segment 단위로 나누어서 저장이 되었는데, 이는 merging과 compaction을 통해 관리 된다. 그러나 이는 range query에 대해 굉장히 비효율적이며, hash collision을 해결하는게 쉽지 않다. 여기서 발전 한것이 LSM Tree이다. LSM Tree는 SSTable (Sorted String Table)이라는 segment file에 저장하고 key-value를 key로 sorting하게 된다. LSM Tree는 Cassandra, HBase, Lucene 등에 쓰인다. 이 경우 모든 index를 memory에 저장할 필요 없고, 각 segment를 mergesort로 이용해 합치는 기법을 쓰고, 메모리에 sparse index를 놓아 각 key의 byte offset으로 따라가게 한다. SSTable은 Red Black Tree 등을 이용하며, write는 memtable에 작성하게 된다 (인메모리 트리 데이터 구조). 이러한 memtable이 커지게 되면 disk에 SSTable로 작성된다. 이러한 LSM Tree는 B+Tree보다 빠르게 Write할 수 있다.

Page-Oriented Engine

흔히 대부부분의 DMBS에 사용되고 있다. Segment를 관리하는 거와 다르게 database를 pages라는 고정 크기로 나누게 되고, root로 부터 시작되어 treeㄹ르 만들게 된다. Update, add, delete는 모두 balance하게 유지하려 하며 항상 depth는 O(log n)을 가지게 된다. B Tree에서 발전된것이 B+ Tree로 포인터가 leaf node에만 있고, 옆의 sibling을 향하는 포인터가 추가적으로 있다. B+Tree는 LSM Tree보다 빠르게 Read할 수 있다.

추가

Secondary Index는 unique하지 않은 index로 여러개의 index를 만들 수 있다. Index에 value를 저장하는 종류로는 nonclustered index, clustered index, covering index가 있는데, nonclustred index는 row가 위치한 heap file을 가지고 있어 row를 reference한다면, clustered index는 실제 row나 document를 가지고 있다. 따라서 clustered index 자체는 검색 속도 자체는 더 빠르다. Covering index는 절충안으로 색인 안에 칼럼을 일부 저장한다.

OLAP vs OLTP

OLTP = Online Transactional Processing (실제 레코드 저장) OLAP = Online Transactional Processing (분석을 위해 사용)

특성 OLTP OLAP
읽기 적은 수의 레코드, 키 기준으로 전체 칼럼을 많이 가져옴 많은 레코드에 대한 aggregation, 일부 칼럼 접근
쓰기 사용자가 입력, 낮은 지연시간 필요 ETL 또는 스트리밍
사용자 많은 일반 유저/소비자 내부 분석가
데이터 표현 데이터의 최신상태 이벤트의 이력
데이터양 적음 많음
병목 디스크탐색 (키의 데이터를 찾아야함) 디스크 대역폭 (짧으시간에 여러 레코드 스캔해야함)

OLAP용 Database를 보통 Data Warehouse라 한다. 관계형 모델을 보통 사용하며 (Redshift 등) 분석용 스키마로는 Star Schema나 Snowflake Schema를 사용한다.

Column-oriented database

OLAP의 사실 테이블에 접근하는 경우 특정 칼럼만 접근하는 경우가 많다. 따라서, 일반 Row 지향 저장소를 가지게 되면 모든 Row를 적재한뒤 필터링을 해야하는 반면, Column 지향 저장소를 사용하게 되면 특정 칼럼만 가져오면 된다. 칼럼 지향 저장소의 각 로우가 같은 순서라는 것을 이용하여 칼럼을 정렬하고, 비트맵 부호화한뒤 런랭스 부호하로 더 칼럼을 압축 할 수 있다. 이러한 경우는 쓰기로 LSM Tree방식을 사용한다. 대표적으로 Redshift, MariaDB, Snowflake가 있다.