[Design] 데이터 모델과 쿼리

지극히 주관적인 요약

1. 데이터 모델 중요성

데이터 모델은 소프트웨어 개발에서 제일 중요한 부분 중 하나이다. 왜냐하면 데이터 모델은 소프트웨어가 어떻게 작성됐는지 뿐만 아니라 해결하려는 문제를 어떻게 생각하는지에 대해서도 지대한 영향을 미치기 때문이다.

데이터 모델은 여러 계층을 이루며 구성되는데 각 계층의 핵심적인 고민거리는 다음 하위 계층(down stream)을 위해 데이터를 어떻게 전달해야 하는지이다. 이는 단순히 application과 persistence 사이 뿐만이 아니라 application 내에서 또는 application 간에도 고민이 되어야 한다.

각 계층은 명확한 데이터 모델을 제공해 하위 계층에게 복잡성을 숨긴다. 이러한 추성화를 통해 다른 그룹의 사람들이 그들의 관점에서 데이터를 바라보게 하고 더 효율적으로 업무할 수 있도록 한다.

2. 데이터 모델 별 특징

Relational DB Model

장점 - 조인, 다대일, 다대다 관계를 잘 지원함. 데이터 일관성을 잘 보장함.

가장 범용적으로 사용되는 데이터 모델은 RDB 형태의 모델로 비즈니스 데이터 처리를 위한 transaction processing 및 batch processing에 자주 사용된다. 1990년에 이전에는 다양한 데이터 모델이 난립했지만 오랜 기간 발전해 오면서 다른 모델을 평정했다.

Application의 데이터를 관계형 DB의 논리 스키마인 테이블에 저장하기 위해서는 소스코드와 RDB 모델 간의 전환 계층이 필요하다. 이러한 모델 사이의 분리를 **임피던스 불일치(Impedance mismatch)**라고 한다. ActiveRecord나 Hibernate같은 ORM,object relation mapping 프레임워크가 전환 게층에 필요한 소스코드의 양을 줄여주지만 두 모델간의 차이를 완전히 커버할 수는 없다.

NoSQL

Not only SQL의 준말로 SQL 외에 다양한 형태의 데이터 모델들을 일컫는 말이다. 주로 대규모 데이터셋을 높은 처리량through put으로 처리하거나 RDB에서 제공하지 않는 다양한 형태의 쿼리를 제공하기 위해서 사용된다. 현재 NoSQL은 대부분 SQL을 대체하기 위해서 사용되는 것이 아닌 SQL에서 제공하지 못하는 기능들을 추가적으로 제공하여 보완하는 역할로 사용된다.

Document Model

장점 - 스키마 유연성(schema on read), 지역성으로 인한 성능 향상, 임피던스 불일치 완화

높은 수준의 정규화Normalization로 인해서 사용자가 특정 데이터를 얻기 위해서는 여러 테이블로부터 join을 통해 데이터를 구해야 한다. 이를 보완하기 위해서 XML이나 JSON형태의 문서를 통해 데이터 모델을 구성하기도 한다. 이를 사용하면 임피던스 불일치로 인한 불편함을 조금은 해소할 수 있다. JSON으로 데이터를 저장하면 다중 테이블 스키마보다 데이터의 지역성locality가 더 나아진다. 하지만 문서 모델에서는 스키마의 유연성으로 인한 문제점도 존재한다.

만약에 ManyToOne, ManyToMany 관계와 같이 데이터의 join이 필요한 경우는 모델에 적합하지 않다. 그리고 application 초기 버전에서 데이터 간에 관계가 형성되지 않아(join-free) 문서 모델이 적합해 보일지라도, 기능이 추가되면서 데이터는 점차 상호 연결되는 경향이 있다. 따라서 이를 고려한 모델링이 필요하다.

문서 모델을 저장하기 위한 문서 데이터베이스는 상위 레코드 내에 중첩된 레코드를 저장함으로써 OneToMany 관계를 형성한다. 만약 위에서 이야기 한 것처럼 ManyToOne, ManyToMany 관계를 표현하기 위해서는 RDB와 마찬가지로 외래키와 유사한 문서참조(document reference)를 통해서 데이터를 참조한다.

주의점

  • 문서 내 중첩 항목을 바로 참조할 수 없어서, 계층적으로 접근이 이루어져야 한다. 따라서 너무 많은 계층을 가지지 않도록 주의해야 한다.
  • 문서 내의 데이터를 application 레벨에서 join하여 처리할 수 있으나 DBMS를 사용하는 것 보다 성능이 떨어진다.
  • 문서가 너무 큰 경우, 문서의 일부를 조회하기 위해서 전체 문서를 다 읽어야 한다. 문서 크기를 작게 유지하고 문서의 크기가 커지는 것을 방지해야 한다.

Graph model

데이터에서 대부분의 관계가 ManyToMany인 경우에 사용한다. 그래프는 두가지 유형의 객체로 이루어지는데 정점(vertex)와 간선(edge)이다. 많은 유형의 데이터를 그래프로 모델링 할 수 있는데 일반적인 유즈케이스는 다음과 같다.

사용예

  • 소셜그래프 - vertex는 사람이고 edge는 사람들과의 관계 객체를 나타냄
  • 웹 그래프 - vertex는 웹 페이지고 edge는 다른 페이지에 대한 링크를 나타냄
  • 도로나 철도 네트워크 - vertex는 교차로이고 edge는 도로나 철로를 나타냄

구조나 질의 방법에 따라서 크게 속성 그래프트리플 저장소 모델로 나뉜다.

속성 그래프 특징

  • vertex 구성 (vertextID, outgoing edges, incoming edges, key-value collection)
  • edge 구성 (edgeId, head vertex, tail vertex, relation label, key-value collection)
  • 관계를 제한하는 스키마가 없으며, vertex가 주어지면 vertex 유입과 유출 간선을 효율적으로 찾을 수 있고 그래프를 순회할 수 있다.
  • 다른 유형 관계에서 서로 다른 레이블을 통해 단일 그래프에 다른 유형의 정보를 쉽게 부여할 수 있다.
  • 사이퍼 질의 언어로 속성 그래프를 질의한다.

트리플 저장소 모델

  • 속성 그래프 모델과 유사하고 비슷한 아이디어를, 다른 용어를 통해 풀어낸다. 트리플 저장소 모델에서는 모든 정보를 주어-서술어-목적어 처럼 간단한 세 부분의 구문형식으로 저장한다.

정리

RDBMS와 문서형 DBMS가 시간이 지남에 따라 점점 더 비슷해지고 있다. 각 데이터 모델이 서로 부족한 부분을 보완해 나가고 있기 때문이다. 이는 긍정적인 방향이며 application 개발자는 이를 적절히 조합하여 사용하면 된다.

3. 모델 질의 언어

관계형DB 모델을 위한 SQL은 선언형 질의 언어인 반면에, 계층형인 IMS와 네트워크 모델인 코다실은 명령형 코드를 사용하여 질의한다.

Imperative Language Query

명령형 언어는 우리가 많이 사용하는 프로그래밍 언어(C, Java, Kotlin 등)에서 데이터를 처리하는 방식으로 특정 순서로 특정 연산을 수행하도록 컴퓨터에게 지시한다.

fun getSharks : MutableList<String> {
    val sharks = mutalbeListOf<String>();
    animals.filter("Sharks".equals(it.family))
           .forEach(sharks::add)
    return sharks
}

Declarative Language Query

선언형 언어는 관계대수(relational algebra)와 유사한 방식으로 데이터를 얻기 위한 방법을 기술하는 것이 아니라 데이터의 패턴, 결과가 충족해야 하는 조건과 데이터를 어떻게 변환할지를 지정한다.

장점

  • 명령형 언어에 비해서 쉽다.
  • DB 엔진 상세 구현이 숨겨져 있어 쿼리 변경 없이 최적화 작업을 수행할 수 있다.
  • 쿼리에 대한 순서가 보장되어 있지 않음으로 내부적인 질의에 대한 순서가 바뀌어도 상관이 없다.
  • 종종 병렬 실행에 적합하다.

이러한 장점은 프론트엔드 소스코드에서도 활용되어 javascript 대신 CSS selector , XSL 등을 통해 선언형 질의를 수행한다.

MapReduce Query

다수의 범용 컴퓨터로 대량의 데이터를 처리하기 위한 프로그래밍 모델로 google에 의해서 널리 알려졌다. 몽고DB, 카우치DB를 포함한 NoSQL 데이터 저장소에서 제한된 형태의 MR을 사용한다. 이 메커니즘은 많은 문서를 대상으로 read-only 질의를 수행할때 사용한다. 이들 저장소에서의 MR질의는 선언형 질의와 명령형 질의 중간에 위치한다.

db.observation.mapReduce(
	function map(){
        // process 
    }, 
	function reduce(key,values){
        // reduce 
    }, 
	{
        query: {family: "sharks"} 
        out: "monthlySharkReport" 
    })

맵리듀스에서 사용되는 함수는 pure function으로 입력으로 전달된 데이터만 사용하여 추가적인 부수효과(side effect)가 없어야 한다.

Graph query

Cypher query - 속성 그래프를 위한 선언형 질의 언어

Semantic Web - 트리플 저장소 형태를 띄지만, 트리플 저장소와는 관계가 없다.

SPARKQL - RDF 데이터 모델을 사용한 트리플 저장소 질의언어. Cyper query 보다 먼저 만들어졌지만 후에 cypher query를 차용함으로써 비슷해졌다. 하지만 Cypher query보다 매우 간결하다.

데이터 로그 … 생략


4. 정리

역사적으로 데이터를 하나의 큰 트리(계층모델)로 표현하려고 노력했지만 다대다 관계를 표현하기에는 트리구조가 적절하지 않았다. 이를 해결하기 위해서 관계형 모델이 고안되었으며 범용적으로 사용됨

일부 application에서는 관계형 모델이 효율적이지 않은 것을 확인하고 NoSQL을 사용하기 시작했으며 이에는 크게 다음과 같은 DB가 존재한다.

  • 문서 데이터베이스 - 데이터가 문서 자체에 포함되어 있어 하나의 문서와 다른 문서간 관계가 거의 없음.
  • 그래프 데이터베이스 - 문서 데이터베이스와 반대로 잠재적으로 모든 것이 관련있는 경우 사용
  • (추가) 칼럼 기반 데이터베이스 - 특정 키 값에 대한 값을 칼럼 또는 칼럼 패밀리 형태로 저장하는 구조로 스키마 변경이 자유롭고 키 값을 통한 랜덤 액세스가 높은 처리량과 빠른 응답시간으로 수행됨
  • (추가) 전문검색(full text search) - 문서들을 구성하는 단어들에 대한 역인덱싱을 통해 빠르게 문서를 검색할 수 있는 모델

이러한 데이터 모델은 하나가 우위를 선점하는 것이 아닌 시스템의 목적에 맞는 모델을 사용해야 한다는 것이다.

각 데이터 모델은 고유한 질의 언어나 프레임워크를 제공한다.

… 그래프 데이터 모델은 SNS 또는 카카오 같은 플랫폼 기업의 특정 비즈니스에서 활용되고 있긴한데 크게 와닿지가 않는다. 실제로 모델 구조에 따른 성능 차이나 특정 비즈니스에 적용해 보지 않으면 모델이나 쿼리가 스며들지 않을 것 같다.