-
Cypher — SQL은 알지만 그래프 쿼리는 처음인 사람에게IT 2026. 5. 27. 21:00
SQL을 한 번이라도 써 본 사람이라면 다음 같은 표현이 익숙할 것이다.
SELECT name FROM users WHERE id = 42;표(table)에서 조건에 맞는 행을 골라 컬럼 값을 가져온다. 데이터가 표 형태로 정리돼 있을 때 가장 자연스러운 표현이다.
그런데 데이터가 표가 아니라 관계의 그물일 때는 어떨까? 사람 A가 B와 친구이고 B는 C·D와 친구이고 D는 다시 A와 친구라면, "A에서 출발해 친구의 친구의 친구로 3홉 안에 도달 가능한 모든 사람"을 묻는 SQL은 의외로 어색하다. 같은 테이블을 자기 자신과 세 번 JOIN하고 중복을 걸러야 한다. 표라는 모양 자체가 관계의 자연스러운 표현이 아닌 자리가 분명히 있다.
이런 자리를 위해 만들어진 게 그래프 쿼리 언어, 그 중 가장 널리 쓰이는 게 Cypher다. 이 글은 SQL은 익숙하지만 Cypher는 처음인 사람에게 — Cypher가 무엇이고, 왜 만들어졌고, 어떤 문제를 어떻게 푸는지를 풀어 본다.
1. Cypher가 뭔지부터
Cypher는 "그래프 데이터를 다루는 쿼리 언어"다. 2011년 Neo4j(그래프 데이터베이스 회사)가 자기 제품용으로 만들었고, 2024년 ISO 표준 GQL(Graph Query Language)로 정식 채택됐다. 지금은 Neo4j 외에도 Memgraph·Kuzu·RedisGraph 등이 같은 문법을 지원한다 — SQL이 여러 RDBMS에서 같이 통하는 것과 비슷한 구도다.
핵심 비교는 간단하다.
- SQL — 표(table)와 행(row)을 다룬다. "WHERE 조건"으로 필터링, "JOIN"으로 두 표를 잇는다.
- Cypher — 노드(node)와 관계(relationship)를 다룬다. "MATCH 패턴"으로 그래프 모양을 찾는다.
가장 인상적인 특징은 ASCII art 같은 문법이다. 노드는 `()`로 묶고, 관계는 `-[]->`로 그린다. "A가 B에게 KNOWS 관계로 연결돼 있다"는 다음과 같이 적는다.
(a:Person)-[:KNOWS]->(b:Person)괄호 안에 노드의 라벨(Person)이 들어가고, 화살표 사이의 대괄호에 관계의 종류(KNOWS)가 들어간다. 코드에서 그래프 그림이 그대로 보인다는 게 Cypher의 첫 인상이다.
2. 왜 하필 이름이 "Cypher"인가 — 영화 매트릭스에서 따온 이름
이름 자체에 작은 이야기가 있다. Neo4j 창립진은 영화 매트릭스(The Matrix, 1999)의 팬이었고, Cypher라는 캐릭터의 이미지에서 직접 이름을 따왔다.
영화 속 Cypher는 매트릭스 화면에 흐르는 녹색 코드(데이터)를 날것 그대로 읽어 의미를 추출하는 인물이다. "이 코드 흐름에서 금발 여자가 보인다"고 말하는 그 장면. Neo4j 창립진은 같은 발상을 자기들 쿼리 언어에 담고 싶었다 — "복잡하게 얽힌 그래프 데이터를 인간이 직관적으로 읽고 패턴을 알아보는 도구". 표 데이터를 한 줄씩 SELECT하는 SQL의 발상과 다른, "전체 그물의 모양을 그대로 인식한다"는 그래프 친화적 사고가 이름에 박혀 있다.
덤으로, cypher는 cipher(암호·기호)의 변형 표기이기도 하다. "그래프라는 숨겨진 구조를 읽어 내는 기호 체계"라는 두 번째 의미가 같이 묻어 온다. 이름 하나에 영화 오마주와 단어 본래 뜻이 겹치는 셈이라, Cypher의 정신을 한 단어로 압축한 셈이다.
3. 왜 만들어졌나 — SQL JOIN 지옥의 탈출구
SQL로 그래프 같은 데이터를 다뤄 본 사람이라면 "JOIN 지옥"이라는 표현에 공감할 것이다. 친구의 친구의 친구를 찾기 위해 같은 표를 세 번 JOIN해서 결과가 폭발적으로 늘어나고, 그 결과를 DISTINCT로 정리하느라 쿼리가 30줄을 넘는 경험.
같은 질문을 SQL과 Cypher로 적어 본다.
다이어그램 설명. 같은 질문에 대해 SQL은 self-JOIN을 손으로 풀어야 하고 Cypher는 화살표 패턴이 그래프 모양 그대로 보인다. 홉 개수가 늘어날수록 격차가 커진다 — 3홉 SQL은 6~8 JOIN으로 30줄을 넘기고, Cypher는
[:KNOWS*1..3]한 표현으로 끝난다. 이게 Cypher가 만들어진 진짜 이유다 — 표가 아닌 그물 모양의 데이터를 표 언어로 짜는 건 부자연스러워서.4. 기본 문법 — 그림을 그리듯이 쿼리를 짠다
Cypher 문법의 핵심은 두 가지 시각 기호다.
()— 노드. 빈 괄호는 "아무 노드", 안에 라벨을 넣으면 그 종류의 노드. 예:(p:Person)는 "Person 라벨의 노드".-[]->— 관계(edge). 대괄호 안에 관계의 종류를 적는다. 예:-[:KNOWS]->는 "KNOWS 관계로 향함". 화살표 방향이 곧 관계 방향.
이 둘을 묶어서 그래프 모양 그대로 패턴을 만든다.
-- 1. A가 누구를 KNOWS하는가 MATCH (a:Person {name: 'A'})-[:KNOWS]->(other) RETURN other.name; -- 2. A의 친구의 친구 (2홉) MATCH (a:Person {name: 'A'})-[:KNOWS]->()-[:KNOWS]->(fof) WHERE fof <> a RETURN DISTINCT fof.name; -- 3. A에서 출발해 1~3홉 안에 도달 가능한 모든 사람 (가변 길이) MATCH (a:Person {name: 'A'})-[:KNOWS*1..3]->(reachable) RETURN DISTINCT reachable.name; -- 4. A와 B 사이의 최단 경로 (몇 다리 건너야 하나) MATCH path = shortestPath( (a:Person {name: 'A'})-[:KNOWS*]-(b:Person {name: 'B'}) ) RETURN length(path) AS hops;코드 설명. 네 가지가 모두 그래프 그림을 코드로 옮긴 모양이다.
()-[:KNOWS]->()패턴이 화살표 그림이고,*1..3은 "1~3홉을 허용"이라는 가변 길이 지정이다. SQL이 같은 일을 표 JOIN으로 시뮬레이션해야 하는 것과 다르게, Cypher는 "머릿속에 그린 그래프 모양을 그대로 받아 적는다"는 감각으로 짤 수 있다. 처음 보면 낯설지만, 한 시간만 보면 SQL보다 그래프 표현이 훨씬 직관적으로 느껴진다.5. 어떤 문제를 푸는가 — Cypher가 빛나는 5가지 자리
모든 데이터를 그래프 DB에 넣을 필요는 없다. Cypher가 결정적으로 빛나는 자리는 다음 다섯 가지다.
다이어그램 설명. 다섯 가지 모두 "노드와 관계의 그물"을 다룰 때 자연스러운 질문들이다. SQL로 못 푸는 건 아니지만 코드가 길어지고, 가독성이 떨어지며, 성능도 그래프 DB가 훨씬 빠르다. 반대로 "이 표에서 컬럼별 합계" 같은 표 친화 질문은 SQL이 압도적이다. 도구는 데이터의 모양에 맞춰 고른다.
6. 우리 맥락 — 코드 베이스를 그래프로 다루기
코드 베이스는 사실 거대한 그래프다.
- 노드: 함수·클래스·모듈·repo·서비스
- 관계: 함수 A가 함수 B를 CALL, 모듈 X가 모듈 Y를 IMPORT, repo P가 repo Q에 DEPENDS_ON
이걸 그래프 DB에 넣으면 코드 위키·정적 분석·영향 분석 같은 작업이 한 줄 쿼리로 풀린다. 실제 시나리오를 보자.
-- 시나리오 A: 이 함수를 바꾸면 어디까지 영향이 가는가 -- (역방향 호출 트리 — 누가 나를 부르는가, 3홉까지) MATCH (target:Function {name: 'parseConfig'}) <-[:CALLS*1..3]-(caller:Function) RETURN DISTINCT caller.name, caller.file ORDER BY caller.name; -- 시나리오 B: 순환 import가 있는가 (모듈 간 사이클 감지) MATCH (m:Module)-[:IMPORTS*1..5]->(m) RETURN m.name AS in_cycle; -- 시나리오 C: 가장 많이 import되는 hub 모듈 top 10 MATCH (m:Module)<-[:IMPORTS]-(other) RETURN m.name, count(other) AS inbound ORDER BY inbound DESC LIMIT 10; -- 시나리오 D: 이 repo의 변경이 영향을 미치는 다른 repo들 MATCH (src:Repo {name: 'gpu-scheduler'}) <-[:DEPENDS_ON]-(downstream:Repo) RETURN downstream.name; -- 시나리오 E: 두 함수 사이의 호출 경로 (얼마나 멀리 떨어졌나) MATCH path = shortestPath( (a:Function {name: 'handleRequest'}) -[:CALLS*]-> (b:Function {name: 'writeToDB'}) ) RETURN [node IN nodes(path) | node.name] AS callChain, length(path) AS hops;코드 설명. 다섯 시나리오 모두 코드 분석에서 자주 마주치는 질문이다. 시나리오 A는 리팩터링 직전 "이 함수를 바꾸면 깨질 곳"을 미리 본다 — 역방향 화살표
<-[:CALLS]-로 호출자를 따라간다. 시나리오 B는 모듈 시스템에서 가장 잡기 까다로운 circular import를 한 줄로 감지한다 —(m)-[*1..5]->(m)이 "자기 자신으로 돌아오는 경로"라는 그래프 그림을 그대로 옮긴 것. 시나리오 D는 cross-repo 의존성 분석으로, 한 인프라 repo 수정이 어느 서비스 repo에 영향 줄지 한 줄로 본다.이런 질문들을 SQL로도 풀 수 있긴 하다. 그러나 "이 함수의 호출 트리에서 5홉 안의 모든 함수"를 SQL로 적으려면 recursive CTE를 짜야 하고, 결과가 같은 함수를 여러 경로로 도달했을 때 중복 처리하는 등 보일러플레이트가 폭발한다. Cypher는 그래프 모양을 그대로 받아 적기 때문에, 같은 작업을 1/10 길이로 끝낸다.
7. 한계와 트레이드오프 — Cypher가 항상 정답은 아니다
Cypher가 매력적이지만 모든 경우에 우선해서 쓸 만한 도구는 아니다. 다음 다섯 가지를 함께 고려한다.
- 그래프 규모가 작으면 과한 도구 — 노드 수천 개 수준이면 SQL + 인덱스로도 충분하다. 그래프 DB는 별도 서버 프로세스를 띄워야 하므로, 작은 규모에선 운영 부담이 더 크다.
- 벤더 락인 위험 — Cypher는 표준 GQL이 됐지만 실제 지원 도구가 SQL 만큼 많지 않다. Neo4j·Memgraph·Kuzu 정도. 미래에 백엔드를 갈아탈 때 옵션이 좁다.
- 표 친화 질문엔 약함 — "이 컬럼 합계 / 평균 / 표준편차" 같은 집계는 SQL이 훨씬 자연스럽다. 데이터의 80%가 표 친화면 SQL이 더 좋다.
- 학습 곡선 — SQL은 거의 모든 개발자가 한 번씩 배운 상태지만, Cypher는 새로 가르쳐야 한다. 1~2시간이면 기본은 익히지만, 팀 전체에 깔리려면 시간이 든다.
- 관계형과 그래프 혼합 데이터 — 사용자 정보(표 친화) + 친구 관계(그래프 친화)가 섞여 있으면 두 도구를 같이 써야 한다. 결국 결합도 관리 부담이 생긴다.
그래서 실용적인 선택은 종종 "SQL로 80%를 처리하고, 그래프 친화 영역만 그래프 도구 또는 NetworkX 같은 인메모리 라이브러리로 처리"다. 예를 들어 22 repo 규모의 코드 베이스(노드 ~5,000개)라면 SQLite + 가벼운 그래프 라이브러리로 충분하고, 본격 Cypher는 노드 수가 10만을 넘기 시작할 때 진가를 발휘한다.
마무리 — 그래프 모양 데이터엔 그래프 언어를
Cypher의 진짜 가치는 "세련된 새 문법"이 아니라 "데이터의 모양을 그대로 받아 적게 해 주는 자연스러움"이다. 친구 관계도 그래프, 코드 호출 관계도 그래프, 의존성도 그래프 — 세상에는 표보다 그물 모양으로 더 잘 표현되는 데이터가 의외로 많다. 그런 데이터를 표 언어로 짜는 건 어색하고, 결국 가독성과 유지보수성을 갉아먹는다.
SQL을 안다는 건 이미 좋은 출발점이다. Cypher는 그 위에 "화살표 그림"이라는 한 가지 새 시각만 더 얹으면 된다. 그래프 모양 질문이 자주 떠오르는 자리(코드 분석·관계 추적·영향 분석 등)라면, 한 번쯤 Cypher로 표현해 보면 좋겠다. "이게 SQL이었으면 30줄이었겠다"는 순간이 의외로 빨리 온다.
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
NetworkX 대표 알고리즘 3선 — 코드 베이스 분석에서 한 줄로 끝나는 일들 (0) 2026.05.27 가벼운 그래프 데이터 처리 — NetworkX + SQLite WAL 조합의 정체와 효과 (0) 2026.05.27 코드 위키는 mermaid를 얼마나 쓸까 — React 위키 115개·Express 위키 221개 실측과 의미 (0) 2026.05.26 코드 위키 8섹션 표준 — Overview부터 Glossary까지 하나씩 풀어보기 (0) 2026.05.26 DeepWiki·CodeWiki·deepwiki-open — 같아 보이는 코드 위키 도구 세 개의 진짜 차이 (0) 2026.05.26 한국어 자막 sync는 한 알고리즘으로 안 된다 — 4단 fallback을 쌓아 올린 이유 (0) 2026.05.25 Seedance 2.0 fast 영상의 음성이 1.3초 빨리 나왔다 — 재생성 0원, ffmpeg adelay로 5초만에 해결 (0) 2026.05.24 ffmpeg concat이 Seedance 클립 두 번째부터 깨졌다 — video duration이 진실의 원천 (0) 2026.05.24 ffmpeg -c copy로 0.5초 trim했더니 0초 trim됐다 — keyframe-aligned의 함정 (Seedance 후처리 사례) (0) 2026.05.24 Seedance 2.0 fast 영상의 첫 0.5초가 사진처럼 정지된 이유 — photo prefix 자동 제거 (0) 2026.05.23