소프트웨어에서 데이터를 저장, 표현, 조작하는 다양한 방법을 알아보자.
- 관계형 모델
- 문서 모델
- 그래프 기반 데이터 모델
1. 관계형 모델과 문서 모델
1.1. 관계형 모델
메인프레임 컴퓨터에서 수행된 비즈니스 데이터 처리, 트랜잭션 처리, 일괄처리를 하기 위해 사용됨. 개발자는 DB 내부 데이터 표현에 대해 많이 고민해야 했지만 관계형 모델의 목표는 정리된 인터페이스 뒤로 구현 세부 사항을 숨기는 것. 60년대 부터 사용되기 시작했지만 요즘 대부분의 서비스들도 여전히 관계형 데이터베이스를 통해 제공됨.
1.2. 객체 관계형 불일치 (일대다 관계)
- 객체지향 프로그래밍 언어의 확산
- 관계형 모델로 표현하기 복잡한 데이터 계층 구조
- 임피던스 불일치
- json 모델 제시
- NoSQL 데이터베이스 확산
1.3. NoSQL
오픈소스, 분산 환경, 비관계형 데이터베이스에 적절함. 대규모 데이터셋, 높은 쓰기 처리량, 뛰어난 확장성을 가지고 있음. 오픈소스 소프트웨어 선호도 확산. 특수 질의 동작. 동적이고 표현력이 풍부한 데이터 모델.
관계형 + 비관계형 모델 = 다중 저장소 지속성 (polyglot persistence)
1.4. 다대일과 다대다 관계
중복된 데이터를 정규화하려면 참조키를 사용하는 다대일 관계가 필요함. 관게형 모델은 조인이 쉽기 때문에 많이 사용됨. 문서 모델에서는 조인에 대한 지원이 부족하기 때문에 많이 적합하지 않음.
추천서
- 추천받은 사용자 이력서: 추천인의 이름, 사진
- 추천인의 이름 변경: 추천인이 작성한 모든 추천서에 새로운 사진 반영
- 추천서는 추천인의 프로필 참조
1.5. 문서 데이터베이스는 역사를 반복하고 있나?
70년대 가장 많이 사용된 데이터베이스는 IBM의 IMS. 계층 모델을 사용.
- (문서 데이터베이스의 JSON 모델과 유사) 조인을 지원하지 않아 다대다 관계 표현에 어려움이 있음.
- 데이터를 중복할 것인가, 수동으로 참조할 것인가 해결책으로 네트워크 모델과 관계형 모델이 제시됨.
1.5.1. 네트워크 모델
계층 모델에서는 하나의 부모만 존재하지만 네트워크 모델의 레코드는 다중 부모가 있을 수 있음. 최상위 레코드에서 부터 연속된 연결 경로를 따르는 방법. 목록의 맨 앞에서 시작해서 원하는 레코드를 찾을 때까지 한 번에 하나의 레코드를 보는 방식. 레코드 목록을 반복해 접근 경로를 따라 데이터베이스의 끝에서 끝까지 커서를 움직여 수행.
1.5.2. 관계형 모델
관계(테이블)는 단순히 튜플(로우)의 컬렉션. 중첩 데이터 구조를 여러 테이블에 데이터를 배치함. 테이블의 로우로 배치된 데이터는 특정 조건에 일치만 한다면 외래키 관계에 대해 신경 쓰지 않고 읽고 쓸 수 있음. 쿼리를 엔진이 알아서 최적화 해줌.
1.5.3. 문서 데이터베이스와 비교
관계형 모델에서는 외래키 문서 모델에서는 문서 참조
1.6. 어떤 데이터 모델이 애플리케이션 코드를 더 간단하게 할까?
애플리케이션 데이터가 문서와 비슷한 구조라면 문서 모델을 사용하는 것이 좋음.
- 문서와 비슷한 데이터를 관계형 데이터로 찢는 것은 복잡한 스키마와 애플리케이션 코드를 발생 시킴.
애플리케이션에서 다대다 관계 처럼 상호 연결이 많은 데이터의 경우라면 관계형 모델이 더 적합함.
- 문서 모델을 사용하면 애플리케이션 내에 복잡한 조인 로직이 필요함.
애플리케이션에서 어떤 데이터 구조를 사용하느냐에 따라 적합한 모델을 선택해야함.
1.6.1. 문서 모델에서의 스키마 유연성
기본적으로 JSON 데이터는 스키마를 강요하지 않음. 문서 모델은 스키마리스라고 불리지만 강요하지 않을뿐 암묵적인 스키마 존재함.
- 쓰기 스키마: 정적(컴파일 타임) 타입 확인과 유사
- 읽기 스키마: 동적(런타임) 타입 확인과 유사 문서 모델에서는 데이터 타입을 변경할 때 새로운 필드를 가진 문서를 작성하면 됨. 관계형 모델에서는 데이터베이스에 새로운 컬럼을 먼저 추가해야함.
1.6.2. 질의를 위한 데이터 지역성
애플리케이션이 자주 전체 문서에 접근해야 할 때 저장소 지역성(storage locality)을 활용하면 성능 이점이 있음. 지역성의 이점은 한 번에 해당 문서의 많은 부분을 필요로 하는 경우에만 적용됨. 문서를 갱신할 때 보통 전체 문서를 재작성 해야함. 문서를 아주 작게 유지하면서 문서의 크기가 증가하는 쓰기를 피하는 것을 권장. 이 성능 제한 때문에 문서 데이터베이스가 유용한 상황이 줄어듬.
- 구글 스패너: 부모 테이블 내에 테이블의 로우를 교차 배치되게끔 선언하는 스키마를 허용하여 관계형 모델에 지역성 특성을 제공.
- 오라클: 다중 테이블 색인 클러스터 테이블 기능으로 지역성을 제공.
- HBase: 칼럼 패밀리 개념이 지역성 관리에 유사한 목적.
1.6.3. 문서 데이터베이스와 관계형 데이터베이스의 통합
관계형 데이터베이스인 MySQL, Postgresql 등에서 JSON 데이터 타입을 제공함. 문서 데이터베이스의 리싱크DB는 관계형 조인 질의를 지원. 몽고DB 드라이버는 자동으로 데이터베이스 참조를 확인. (클라이언트 조인) 관계형, 문서 혼합 모델은 미래 데이터베이스들이 가야할 올바른 길.
2. 데이터를 위한 질의 언어
- 선언형 질의 언어
- SQL
- 목표 달성 방법이 아니라 데이터 패턴을 명시
- 명령형 API보다 간결하고 쉽게 작성 가능
- 질의를 변경하지 않고 데이터베이스 시스템 성능 향상 가능
- 특정 순서를 보장하지 않으므로 순서가 바뀌어도 상관없음
- 알고리즘이 아니라 패턴을 지정하기 때문에 병렬 실행에 적합함
- 명령형 질의 언어
- IMS, 코다실
- 특정 순서로 특정 연산을 수행하도록 지시
- 데이터베이스는 코드가 순서에 의존하는지 확신할 수 없음
- 명령을 특정 순서대로 수행하게끔 지시하여 다중 코어, 다중 장비에서 병렬 처리가 매우 어려움
2.1. 웹에서의 선언형 질의
스타일을 지정하는 방식의 차이
- CSS: 선언형 질의
- Javascript: 명령형 지의
2.2. 맵리듀스 질의
대량의 데이터를 처리하기 위한 프로그래밍 모델. 일부 NoSQL 데이터 저장소는 제한된 형태의 맵리듀스 지원. (몽고DB) 읽기 전용 질의를 수행할 때 사용. 질의 로직은 처리 프레임워크가 반복적으로 호출하는 조각 코드로 표현. map, reduce 함수를 기반으로 함.
2.2.1. 몽고DB 기준 map, reduce 제약 사항
- 두 함수는 순수 함수여야 함
- 입력으로 전달된 데이터만 사용
- 추가적인 데이터베이스 질의 수행할 수 없어야 함
- 부수 효과가 없어야함
- 이 제약으로 순서 상관없이 실행이 가능하고 장애가 발생해도 재실행 가능
3. 그래프형 데이터 모델
관계형 모델로도 다대다 관계를 다룰 수 있지만 데이터 간 연결이 더 복잡해지면 그래프로 데이터 모델링하기 시작하는 편이 더 자연스러움.
그래프의 두 유형의 객체
- 정점(vertex): 노드나 엔티티
- 간선(edge): 관계나 호(arc)
3.1. 속성 그래프
3.1.1. 정점의 구성 요소
- 고유한 식별자
- 유출(outgoing) 간선 집합
- 유입(incoming) 간선 집합
- 속성 컬렉션 (key-value)
3.1.2. 간선의 구성 요소
- 고유한 식별자
- 간선이 시작하는 정점 (꼬리 정점)
- 간선이 끝나는 정점 (머리 정점)
- 두 정점 간 관계 유형을 설명하는 레이블
- 속성 컬렉션 (key-value)
3.1.3. 관계형 스키마로 속성 그래프 표현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
create table vertices (
vertex_id integer primary key,
properties json
);
create table edges (
edge_id integer primary key,
tail_vertex integer reference vertices (vertex_id),
head_vertex integer reference vertices (vertex_id),
label text,
properties json
);
create index edges_tails on edges (tail_vertex);
create index edges_heads n edges (head_vertex);
- 정점은 다른 정점과 간선으로 연결됨.
- 특정 유형과 관련 여부를 제한하는 스키마는 없음.
- 정점이 주어지면 정점의 유입과 유출 간선을 효율적으로 찾을 수 있고 그래프를 순회할 수 있음.
- 정점을 따라 앞뒤 방향으로 순회 가능.
- 서로 다른 레이블을 사용하면 단일 그래프에 다른 유형의 정보를 저장하면서 모델을 깔끔하게 유지 가능.
https://www.devkuma.com/docs/neo4j/overview/
3.2. 사이퍼 질의 언어
속성 그래프를 위한 선언형 질의 언어. 네오포제이 그래프 데이터베이스용.
1
2
3
4
MATCH
(person) - [:BORN_IN] -> () -[:WITHIN*0..] -> (us:Location {name: 'United States'}),
(person) - [:LIVES_IN] -> () -[:WITHIN*0..] -> (eu:Location {name: 'Europe'})
RETURN person.name
데이터베이스에서 모든 사람을 훑어보는 작업을 시작으로 사람들의 출생지와 거주지를 확인해 기준에 맡는 사람들만 반환.
name 속성에 색인이 있다면 동일하게 두 개의 Location 정점에서 시작해 반대 방향으로 수행도 가능.
- name 으로 미국과 유럽을 나타내는 두 개의 정점을 찾음.
- WITHIN 유입 간섭을 따라 미국과 유럽의 모든 위치 찾기 진행.
- 위치를 나타내는 정점 중 하나에서 BORN_IN, LIVES_IN 유입 간선을 통해 발견된 사람들을 구함.
보통 선언형 질의 언어는 질의를 작성할 때 이처럼 수행에 자세히 지정할 필요가 없고 질의 최적좌기에서 효율적인 전략으로 선택해줌.
3.3. SQL의 그래프 질의
관계형 데이터베이스로 표현된 그래프 데이터는 SQL로 질의할 수는 있지만 질의에 필요한 조인을 미리 알고 있어야함. 그래프 질의에서는 찾고자하는 정점을 찾기 전에 가변적인 여러 간선을 순회해야하여 미리 조인 수를 고정할 수 없음. 재귀 공통 테이블 식 (with recursive) 를 사용할 수 있지만 사이퍼와 비교하면 문법이 매우 어려움.
3.4. 트리플 저장소와 스파클
트리플 저장소 모델은 속성 그래프 모델과 거의 동등. 트리플 저장소에서는 모든 정보를 매우 간단한 세 부분 구문 (three-part statements) 형식으로 저장함.
- subject, predicate, object