데이터 중심 애플리케이션 설계 | 02장. 데이터 모델과 질의 언어

발표자 : 김정수, 박수민

발표자료

챕터의 목적

  • 각 데이터 모델의 대한 차이점과 특성을 이해한다.
  • 만들고자 하는 애플리케이션에 어떠한 데이터 모델이 적절한지 판단할 수 있게 한다.

RDB vs NoSQL

  • 2장에서는 데이터 모델의 차이점에만 집중한다.
    • 그 외 것: 내결함성(5장), 동시성 처리(7장)
  • NoSQL
    • 스키마 유연성, 지역성에 기인한 더 나은 성능
    • 일부 애플리케이션의 경우, 애플리케이션에서 사용하는 데이터 구조와 더 가깝다
  • RDB
    • 조인, N:1, N:N 관계를 잘 지원함

NoSQL

문서와 비슷한 구조를 여러 테이블로 분리하는 관계형 기법의 문제점

  • 다루기 힘든 스키마
  • 불필요하고 복합한 애플리케이션 코드 발생

문서 모델의 제한

  • 문서 내 중첩(nested) 항목을 바로 참조할 수 없다. (관계형은 관련된 key만 있다면 바로 참조 가능, 그러나 key를 찾기 위한 불필요한 선회가 발생할 수 도 있다.)
    • 예) 사용자의 상세 주소를 참조해야할 경우
      • user.address.road.detail
    • 중첩이 너무 깊지 않다면 일반적으로 문제가 되지 않는다.
  • 미흡한 조인 지원
    • 애플리케이션의 경우에 따라 문제가 될 수도 아닐 수도 있다.
  • 다대다 관계가 필요할 경우 비효율
    • 애플리케이션의 복잡도가 증가
    • 애플리케이션에서 처리하는 것은 데이터베이스 내의 특화된 코드로 수행되는 것 보다 성능이 안 좋다.

스미카 유연성

특정 스키마를 강요하지 않는다.

  • 임의의 키와 값을 문서에 추가할 수 있다.
  • 문서에 포함된 필드의 존애 여부를 보장하지 않는다.

접근 방식에 따른 처리 방법 차이

예) user에 first_name을 추가할 경우

// 문서형 모델
// 애플리케이션에서 데이터를 읽는 경우를 처리하는 코드만 있으면 된다.
// (데이터베이스의 변경을 요구하지 않는 방법이지만 좋은 방법 같진 않다. 그냥 방법의 차이를 이해하는 정도로만 여기자.)
if (user?.name && user?.first_name == null) {
    user.first_name = user.name.split(" ")[0]
}
 
 
// 관계형 모델
// 별도의 스키마 변경 및 데이터 마이그레이션 작업 필요
ALTER TABLE users ADD COLUMN first_name test;
UPDATE users SET first_name = substring_index(name, ' ', 2);

저장소 지역성

지역성: 데이터, 프로그램 등에 대해서 특정 부분에 집중적으로 접근하는 성질

자주 전체 문서에 접근해야 하는 경우 저장소 지역성 활용할 수 있다.

  • 정규화된 관계형 모델의 구조보다 역정규화된 문서형 모델의 구조가 성능상 이점이 있다
    • 관계형 모델은 검색을 위해 다중 색인 검색이 필요 → 더 많은 디스크 탐색 필요 → 더 많은 시간 소요
  • 한 번에 해당 문서의 많은 부분을 필요로 하는 경우에만 적용
    • 문서형 모델에서는 작은 부분에만 접근해야 하는 경우에도 전체 문서를 저장해야 하기 때문에 큰 문서에서는 낭비일 수 있다.

일반적으로 문서를 최대한 작게 유지하면서 문서 크기의 증가를 최소화할 것을 권장

  • 이러한 성능 제한 때문에 문서형 모델이 유용한 상황이 많이 줄어든다.

RDB와 NoSQL의 통합

(서로 비슷한 기능을 제공한다는 의미)

RDB

  • MySQL을 제외한 대부분의 RDB는 XML을 지원하여 문서형 모델과 매우 비슷한 데이터 모델을 사용할 수 있다.
  • Postgre 9.3+, MySQL 5.7+, DB2 10.5+: JSON 문서에 대해 비슷한 기능을 제공

NoSQL

  • 리싱크DB: 쿼리에서 관계형 조인을 지원
  • 몽고DB: 드라이버가 자동으로 데이터베이스 참조를 확인 (클라이언트에서 조인 수행, 네트워크 왕복이 추가로 필요, 최적화가 덜 되어 있어서 조인 성능이 좋지 않다)

질의 언어(Query Language)

선언형 vs 명령형

  • SQL의 선언형
  • IMS, 코다실의 명령형 (안 중요)

선언형 질의 언어의 장점

  • 알고자 하는 데이터의 패턴만 지정하면 된다. (어떤 색인과 조인 함수를 사용할지, 어떤 순서로 실행할 지는 데이터베이스의 질의 최적화가 할 일이다.)
    • 충족해야 하는 조건
    • 데이터의 변환 (정렬, 그룹화, 집계 등)
  • 일반적으로 명령형 질의 API보다 더 간결하고 쉽게 작업할 수 있다.
  • 데이터베이스 엔진의 상세 구현이 추상화되어 있어서 쿼리를 변경하지 않고도 데이터베이스의 성능을 향상시킬 수 있다.

웹의 예제

HTML에 style을 적용할 경우

  • CSS는 선언형
  • JS로 DOM API를 사용하는 것은 명령형
  • 선언형이 명령형보다 가독성, 생산성, 유지보수성에서 우수하다.

맵리듀스 질의

(안 중요)

함수형 프로그래밍에 있는 map, reduce 함수를 기반으로 한다.

단점

  • 질의를 작성하는 것 보다 어렵다
  • 선언형 질의 언어는 질의 최적화기가 질의 성능을 높일 수 있는 기회를 제공한다.

몽고DB 2.2에서 집계 파이프라인(aggregate pipeline)이라는 선언형 질의 언어 지원을 추가하였다.

그래프형 데이터 모델

애플리케이션의 데이터 모델이 주로 1:N(트리 구조 데이터)거나 엔티티간 관계가 없다면 문서형 모델이 적합하다.

그러나 N:N 관계가 매우 일반적인 경우라면 그래프형 모델이 적합하다.

그래프 구성 요소

정점(Vertex, 혹은 노드나 엔티티) SpringData에서는 노드엔티티라고 한다. (@NodeEntity) 간선(Edge 혹은 관계나 호(arc))

예시)

  • 소셜 그래프
    • 정점 = 사람, 간선 = 친구관계
  • 웹 그래프
    • 정점 = 웹페이지, 간선 = 링크
  • 도로 네트워크
    • 정점 = 교차로, 간선 = 도로
  • 페이스북
    • 여러 유형의 정점과 간선을 단일 그래프로 유지
    • 정점 = 사람, 장소, 이벤트, 체크인, 코멘트 등
    • 간선 = 사람간 관계, 체크인이 발생한 위치, 누가 어떤 포스트에 코멘트 했는지, 누가 이벤트에 참석했는지

만약 페이스북을 관계형 모델로 만든다면?

  • 사람, 장소, 이벤트, 체크인, 코멘트 등등이 모두 테이블로 정의될 것이다.
  • 그리고 각 테이블 간의 엄청 복잡한 관계들이 필요할 것이다.
  • 그래프 모델을 적용하는 순간 이러한 복잡성들이 단순화된다.

그래프 모델의 종류

  • 속성 그래프 모델
  • 트리플 저장소 모델 (안 중요)

그래프용 선언형 질의 언어

  • 사이퍼(Cypher)
  • 스파클
  • 데이터로그

속성 그래프

정점의 구성 요소

  • id
  • 유출(outgoing) 간선 집합
  • 유입(incoming) 간선 집합
  • 속성 컬렉션 (키-값 쌍)

간선의 구성 요소

  • id
  • 간선이 시작하는 정점(tail vertex)
  • 간선이 끝나는 정점(head vertex)
  • 두 정점 간 관계 유형을 설명하는 레이블
  • 속성 컬렉션 (키-값 쌍)

관계형 스키마를 사용해 속성 그래프 표현하기

CREATE TABLE vertices (
    vertex_id integer PRIMARY KEY,
    properties json
)
 
 
CREATE TABLE edges (
    edge_id integer PRIMARY KEY,
    tail_vertex integer REFERENCES vertices(vertex_id),
    head_vertex integer REFERENCES vertices(vertex_id),
    label text,
    properties json
)
 
 
CREATE INDEX edges_tails ON edges(tail_vertex)
CREATE INDEX edges_heads ON edges(head_vertex)
  • 정점은 다른 정점과 간선으로 연결된다
    • 특정 유형과 관련 여부를 제한하는 스키마는 없다.
  • 정점이 주어지면 정점의 유입과 유출 간선을 효율적으로 찾을 수 있고 그래프를 순회할 수 있다.
  • 다른 유형의 관계에 서로 다른 레이블을 사용하면 단일 그래프에 다른 유형의 정보를 저장하면서 데이터 모델을 깔끔하게 유지할 수 있다.

이런 기능을 통해 그래프는 데이터 모델링을 위한 많은 유연성을 제공한다.

그래프는 발전성이 좋아서 애플리케이션에 기능을 추가하는 경우 데이터 구조 변경을 수용하게끔 그래프를 쉽게 확장할 수 있다.

사이퍼(Cypher)

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

  • 네오포제이(Neo4j) 그래프 데이터베이스용으로 만들어졌다.
  • wiki: 사이퍼는 식으로 나타내는, 프로퍼티 그래프의 효율적인 질의 및 업데이트를 허용하는 선언형 그래프 질의어이다. 사이퍼는 상대적으로 단순하지만 매우 강력한 언어이다. 매우 복잡한 데이터베이스 쿼리들은 사이퍼를 통해 쉽게 표현이 가능하다.

데이터 모델 생성

CREATE
(NAmerica:Location {name:’North America’, type:’continent’}),
(USA:Location {name:’United States’, type:’country’}),
(Idaho:Location {name:’Idaho’, type:’state’}),
(Lucy:Person {name:’Lucy’}),
(Idaho) -[:WITHIN]-> (USA) -[:WITHIN]-> (NAmerica),
(Lucy) -[:BORN_IN]-> (Idaho)

문제. 미국에서 유럽으로 이민 온 모든 사람들의 이름 찾기

MATCH
(person) -[:BORN_IN]-> () -[:WITHIN*0..]-> (USA:Location {name:’United States’}),
(person) -[:LIVES_IN]-> () -[:WITHIN*0..]-> (EU:Location {name:’Europe’})
RETURN person.name

질의 실행 방법

  1. 모든 사람을 조회로 시작 -> 사람들의 출생지와 거주지를 확인 -> 맞는 사람들만 반환
  2. 2개의 Location으로 시작 -> 미국과 유럽의 모든 위치 찾기를 진행 -> leaf 에 해당하는 정점 중 하나에 BORN_IN, LIVES_IN 유입 간선을 통해 발견된 사람들을 반환

선언형의 장점

  • 수행 방법에 대해서 자세히 기술할 필요가 없음
  • 질의 최적화기가 알아서 가장 효율적인 전략을 자동으로 선택

관계형 모델에서 위의 쿼리를 한다면?

  • 가능하지만 어려움
  • 보통 관계형 모델에서는 쿼리에 필요한 조인을 미리 알고 있다. (FROM 절에서 선언)
  • 그러나 그래프 쿼리에서는 찾고자 하는 정점을 위해 여러 간선을 순회해야 한다.
    • 순회가 몇 번 인지 모른다.
    • 조인 수를 미리 고정할 수 없다.

사이버 쿼리에서 -[:WITHIN*0..]-> 로 순회를 매우 간결하게 표현한다. (*0은 0회 이상을 의미)

SQL1999 이후로 가변 순회 경로에 대한 쿼리를 재귀 공통 테이블 식(Recursive common table expression, 이하 Recursive CTE)(WITH RECURSIVE 문)을 사용해 표현할 수 있다.

  • Postgre, DB2, Oracle, SQL Server에서 지원함
  • MySQL 5.7+ 에서는 지원

트리플 저장소와 스파클

(안 중요)

속성 그래프 모델과 거의 동일

  • 단지 동일 개념에 대한 용어만 다르다

데이터를 주어(subject), 서술어(predicate), 목적어(object)로 매우 간단한 세 부분 구문(three-part statements) 형식으로 저장한다.

  • 주어 = 정점
  • 목적어 = 다른 정점 or primitive datatype의 데이터
  • 서술어 = 간선

Turtle

  • wiki: Terse RDF Triple Language (Turtle)는 Resource Description Framework 데이터 모델에서 데이터를 표현하기 위한 구문 및 파일 형식입니다. Turtle 구문은 RDF 쿼리 언어인 SPARQL의 구문과 유사하다.

스파클은 RDF 데이터 모델을 사용한 트리플 저장소 질의 언어이다.

데이터 로그

데이터 모델이 트리플 저장소 모델과 유사

주어, 서술어 목적어 -> 서술어(주어, 목적어)

그래프 데이터베이스 순위

https://db-engines.com/en/ranking/graph+dbms

한 줄 요약 : 그래프 데이터베이스를 사용하고 싶을 경우 Neo4J를 사용하면 된다.

Neo4J

SpringData 지원

https://spring.io/guides/gs/accessing-data-neo4j/

spring-boot-starter-data-neo4j
@NodeEntity
data class Food(
    @Id
    val id: Long? = null,
    val name: String,
}
 
 
interface FoodRepository : Neo4jRepository<Food, Long>
 
 
@NodeEntity
data class Store(
    @Id
    val id: Long? = null,
    val name: String,
    @Relationship(type = "has")
    val foods: Set<Food>,
}
 
 
interface StoreRepository : Neo4jRepository<Store, Long>

Summary

  • 역사적으로 데이터를 하나의 큰 트리로 표현하려고 노력
  • N:N 관계 표현에 적절하지 않음 → 관계형 모델 등장
  • 최근(?) 관계형 모델에도 적합하지 않은 애플리케이션이 있다는 사실을 발견 → 비관계형 데이터 모델인 NoSQL 등장

NoSQL은 두 가지의 주요 갈래가 있다.

  • 문서형 모델
    • 모든 데이터가 문서에 포함하고 문서간의 관계가 거의 없는 경우 사용
  • 그래프형 모델
    • 문서형 모델과 정반대로 모든 것이 잠재적으로 관련 있는 경우 사용

세 가지 모델 모두 현재 널리 사용

  • 한 모델을 다른 모델로 흉내낼 수 있지만 대부분 그 결과는 엉망이다.

문서형 모델, 그래프형 모델의 장점

  • 저장할 데이터를 위한 스키마를 강제하지 않음 → 변화하는 요구사항에 맞춰 애플리케이션을 쉽게 변경할 수 있다.



최종 수정 : 2022-02-17