그래프 데이터베이스 — Neo4j 와 Cypher · 그래프 모델과 적재 · 이론
표가 느려지는 자리에서 그래프가 시작한다
한 줄 요약
그래프 데이터베이스는 표를 대신하는 물건이 아니라, 관계를 따라가는 질의가 표에서 감당이 안 될 때 꺼내는 물건이다. 노드·관계·속성 세 가지로 모델을 세우고, 관계는 조인이 아니라 포인터로 저장된다.
왜 이게 필요했나
송금 앱의 사기 조사팀이 물었다. "이 계좌에서 나간 돈이 세 다리 건너 어디까지 갔나." SQL 로는 transfers 를 자기 자신과 세 번 조인한다. 두 다리면 두 번, 다섯 다리면 다섯 번 — 질문의 깊이가 곧 조인 횟수다. 조인은 매번 인덱스를 타고 상대 행을 찾는 일이라, 깊이가 하나 늘 때마다 비용이 곱으로 늘어난다. "몇 다리인지 모르겠는데 어쨌든 돌아오는 경로" 같은 질문은 재귀 CTE 로 써야 하고, 그 순간 쿼리는 쓰는 사람도 읽기 어려워진다.
그래프 데이터베이스는 이 한 종류의 질문을 위해 저장 방식을 바꿨다. 관계는 별도의 표가 아니라 노드에 붙은 포인터다. 계좌 노드에서 나가는 송금 관계는 그 노드가 직접 들고 있어서, 다음 계좌로 건너가는 데 인덱스 조회가 없다. 이것을 인덱스 없는 인접성(index-free adjacency)이라고 부른다. 세 다리를 건너는 비용은 세 번의 포인터 따라가기이고, 전체 데이터가 커져도 그 비용은 그대로다.
어떻게 동작하나
Neo4j 의 모델은 셋뿐이다.
| 요소 | 무엇인가 | 이 코스의 예 |
| --- | --- | --- |
| 노드 | 사물. 라벨(Label)로 종류를 표시한다 | (:Person) (:Account) (:Device) |
| 관계 | 두 노드를 잇는 방향 있는 선. 종류(type)와 속성을 가진다 | (:Account)-[:TRANSFER {amount: 300000}]->(:Account) |
| 속성 | 노드나 관계에 붙는 키·값 | p.email, t.ts |
Cypher 는 이 모양을 그림처럼 적는다. (p:Person)-[:OWNS]->(a:Account) 를 읽으면 "사람이 계좌를 소유한다" 가 그대로 보인다. 관계에는 반드시 방향이 있지만, 질의할 때는 방향을 무시할 수도 있다(-[:TRANSFER]-).
무엇을 노드로 하고 무엇을 관계로 할지가 모델링의 전부다. 송금을 관계로 두면 "A 가 B 에게" 가 한 선이라 경로 질의가 자연스럽다. 송금 자체에 다른 것(승인자, 환불, 신고)이 매달려야 한다면 송금을 노드로 승격시킨다 — 관계에는 관계를 이을 수 없기 때문이다. 이 코스의 픽스처는 송금·결제·구매를 관계로 두었다. 경로를 걷는 것이 목적이라서다.
실무에서 진짜 중요한 것
첫째, 그래프가 이기는 질문인지 먼저 가린다. "지난달 업종별 결제 총액" 은 관계를 걷지 않는다. 그런 집계는 관계형이나 열지향 저장소가 훨씬 빠르다. 그래프가 이기는 질문은 깊이가 변하는 것 — 몇 다리 건너, 돌아오는 경로, 같은 것을 공유하는 무리 — 이다.
둘째, 모델은 질의에서 거꾸로 세운다. 표는 정규화 규칙이 모양을 정해 주지만 그래프는 그렇지 않다. "어떤 패턴을 MATCH 할 것인가" 를 먼저 적고 그 패턴이 짧아지도록 노드와 관계를 고른다.
셋째, 시작점은 인덱스가 찾고 나머지는 포인터가 걷는다. 그래프라고 인덱스가 필요 없는 것이 아니다. 첫 노드를 이메일이나 id 로 찾는 일은 여전히 인덱스의 몫이고, 그게 없으면 라벨 전체를 훑는다. 이 모듈의 실습에서 제약과 인덱스를 먼저 만들고 적재를 시작하는 이유가 이것이다.