들어가며

PostgreSQL 19는 SQL/PGQ(SQL Property Graph Queries) 를 코어에 들였어요. ISO/IEC 9075-16:2023, 즉 SQL:2023 Part 16으로 표준화된 기능이에요.

그래프 워크로드를 다루려면 Neo4j나 ArangoDB 같은 전용 DB를 띄우거나, PostgreSQL 위에 Apache AGE 확장을 올리는 길이 대표적이었습니다. 데이터는 멀쩡히 관계형 테이블에 들어 있는데 권한, 조직도, 추천 같은 일부 쿼리만 그래프 모양으로 풀고 싶을 때는, 그 절반쯤만 필요한 인프라를 들이는 셈이라 늘 어색했습니다.

SQL/PGQ는 그 회색 지대를 노립니다. 기존 테이블 위에 그래프 뷰를 얹고, 표준 SQL 안에서 그래프 패턴 매칭을 그대로 씁니다.

이 글은 PostgreSQL 19 베타 직전 기준으로 작성되었으며, 정식 출시 전까지 일부 문법이 조정될 수 있습니다. 앞선 PostgreSQL 19 새 기능 총정리의 후속편으로 읽으면 좋습니다.

SQL/PGQ가 푸는 문제

“아이유를 팔로우하는 사용자가 좋아요를 누른 게시물의 작성자"를 표준 SQL로 풀려면 어떻게 써야 할까요. users, follows, liked, posts, authored 다섯 테이블을 차례로 조인해야 합니다.

SELECT DISTINCT author.handle, p.content
FROM users iu
JOIN follows  f        ON f.followee_id = iu.id
JOIN users    follower ON follower.id = f.follower_id
JOIN liked    l        ON l.user_id = follower.id
JOIN posts    p        ON p.id = l.post_id
JOIN authored a        ON a.post_id = p.id
JOIN users    author   ON author.id = a.user_id
WHERE iu.handle = '아이유';

동작은 합니다. 그러나 한눈에 들어오지 않습니다. 어느 컬럼이 출발이고 어느 컬럼이 도착인지, 팔로우의 방향이 어디로 향하는지 매번 머릿속에서 다시 짚어야 합니다. 한 홉만 더 늘려도 조인이 두 줄씩 붙습니다.

SQL/PGQ는 이 코드를 시각적 패턴으로 옮깁니다. 정점은 괄호 (), 간선은 꺾쇠 -[]->. 의도가 그대로 보입니다.

다만 PostgreSQL 19의 첫 구현은 고정 깊이 패턴까지입니다. 정량 패턴(+, *, {2,5})과 가변 길이 경로는 다음 릴리스로 미뤄졌습니다. 이 글에서 다루는 범위는 그 첫 구현입니다.

CREATE PROPERTY GRAPH로 그래프 뷰 정의하기

먼저 그래프를 선언합니다. 데이터는 옮기지 않습니다. 기존 정점 테이블과 간선 테이블을 그래프로 어떻게 볼지를 카탈로그에 기록할 뿐입니다.

아래는 소셜 서비스 도메인을 그래프로 노출하는 예시입니다. 사용자와 게시물을 정점으로, 팔로우, 작성, 좋아요를 간선으로 잡습니다.

CREATE PROPERTY GRAPH social
  VERTEX TABLES (
    users LABEL person PROPERTIES (id, handle, joined_at),
    posts LABEL post   PROPERTIES (id, content, posted_at)
  )
  EDGE TABLES (
    follows
      SOURCE      KEY (follower_id) REFERENCES users (id)
      DESTINATION KEY (followee_id) REFERENCES users (id)
      LABEL follows PROPERTIES (followed_at),
    authored
      SOURCE      KEY (user_id) REFERENCES users (id)
      DESTINATION KEY (post_id) REFERENCES posts (id)
      LABEL authored,
    liked
      SOURCE      KEY (user_id) REFERENCES users (id)
      DESTINATION KEY (post_id) REFERENCES posts (id)
      LABEL liked PROPERTIES (liked_at)
  );

세 가지만 짚으면 충분합니다. VERTEX TABLES는 정점 데이터를 들고 있는 실제 테이블이고, LABEL로 그래프상 노드 이름을 지정합니다. 정점 테이블은 여러 개 둘 수 있어서 여기서는 usersposts 두 종류를 잡았습니다. EDGE TABLES는 간선 데이터를 들고 있는 실제 테이블인데, SOURCE KEYDESTINATION KEY가 화살표의 출발과 도착을 결정합니다. 같은 정점을 잇는 follows와 서로 다른 정점을 잇는 authored/liked가 한 그래프 안에 공존합니다. 마지막으로 PROPERTIES는 그래프 패턴에서 노출할 컬럼만 골라 잡습니다. 모든 컬럼을 자동으로 끌어오지는 않습니다.

CREATE PROPERTY GRAPH는 새 테이블을 만들지 않습니다. users, posts, follows, authored, liked는 그대로 남고, 그 위에 social이라는 그래프 객체 하나가 더 생깁니다. DROP PROPERTY GRAPH social로 언제든 떼어낼 수 있습니다.

GRAPH_TABLE과 MATCH로 패턴 매칭하기

쿼리 쪽 핵심은 GRAPH_TABLE입니다. 그래프 패턴을 받아 관계형 행 집합으로 돌려줍니다. 즉 결과를 다시 일반 SQL의 FROM 절에서 받아 쓸 수 있습니다.

1홉: 아이유를 팔로우하는 사용자

SELECT handle
FROM GRAPH_TABLE (social
  MATCH (iu IS person WHERE iu.handle = '아이유')
        <-[f IS follows]-
        (follower IS person)
  COLUMNS (follower.handle AS handle)
);

화살표가 왼쪽으로 향합니다. “아이유를 팔로우하는 사람들"을 찾는다는 뜻입니다. 같은 의도를 오른쪽 방향으로 쓰려면 패턴의 시작점을 팔로워로 바꾸면 됩니다. 의미는 같지만 가독성은 사람에 따라 갈립니다.

COLUMNS (...) 절은 패턴 안에서 잡은 값을 일반 컬럼으로 투영합니다. 이름이 곧 결과 컬럼명이 됩니다.

3홉: 팔로워가 좋아요 누른 게시물의 작성자

SELECT DISTINCT author.handle, p.content
FROM GRAPH_TABLE (social
  MATCH (iu IS person WHERE iu.handle = '아이유')
        <-[IS follows]-
        (follower IS person)
        -[IS liked]->
        (p IS post)
        <-[IS authored]-
        (author IS person)
  COLUMNS (author.handle, p.content)
);

앞서 일곱 번 조인으로 풀던 쿼리가 패턴 한 덩어리로 줄었습니다. 화살표 방향이 의도와 그대로 일치합니다.

간선 변수 이름은 본문에서 쓰지 않으면 생략해 -[IS liked]->처럼 적을 수 있습니다. 간선 속성을 다시 꺼내야 할 때만 -[l IS liked]->처럼 이름을 붙이면 됩니다.

양방향 매칭은 <-[e]->로 씁니다. 다만 PostgreSQL 19에서는 양방향 자유 매칭이 일부 제한되며, 단방향 두 번으로 풀어쓰는 편이 안전합니다.

내부 동작과 rewriter의 역할

SQL/PGQ는 새 실행 엔진을 들고 오지 않습니다. 파서가 GRAPH_TABLE을 만나면 rewriter가 그래프 패턴을 표준 관계형 트리로 풀어 씁니다. 정점은 RangeTblEntry가 되고, 간선은 출발 테이블, 간선 테이블, 도착 테이블 사이의 3-way 조인이 됩니다. 그 결과 트리는 일반 플래너로 그대로 흘러갑니다.

flowchart TD
    A[GRAPH_TABLE / MATCH] --> B[Parse Tree]
    B --> C[PGQ Rewriter]
    C --> D[관계형 조인 트리]
    D --> E[일반 플래너]
    E --> F[실행기]

    style C fill:#fde68a,stroke:#b45309
    style D fill:#bbf7d0,stroke:#15803d

이 설계가 가져오는 결과는 셋입니다. 우선 기존 인덱스를 그대로 씁니다. 간선 테이블의 (follower_id, followee_id)(user_id, post_id) 같은 복합 인덱스가 그래프 쿼리에서도 그대로 활용됩니다. MVCC와 트랜잭션도 자동으로 따라오니, 별도 그래프 엔진이라면 따로 신경 써야 했을 부분이 사라집니다. EXPLAIN도 여전히 의미가 있어서, 결국 보이는 건 일반 조인 플랜이고 평소 쓰던 튜닝 도구가 다 통합니다.

대신 그래프 쿼리의 성능은 결국 조인 최적화에 종속됩니다. 간선이 많고 선택도가 낮은 패턴은 대량 조인이 될 수 있습니다. 인덱스와 통계 정보가 평소처럼 중요합니다.

PostgreSQL 19에 들어간 것 vs 빠진 것

항목PostgreSQL 19
고정 깊이 패턴 매칭지원
레이블 필터 (v:Person)지원
속성 투영 COLUMNS (...)지원
단방향/다방향 다홉 조합지원
가변 길이 경로 -[e*1..3]->미지원
정량 패턴 +, *, {2,5}미지원
양방향 자유 매칭 일부미지원
BFS/DFS 탐색 순서 지정미지원
CREATE PROPERTY GRAPH DDL지원

정리하면 이렇습니다. 모양이 정해진 그래프 질의는 PostgreSQL 19에서 곧장 풀 수 있고, 모양이 가변인 그래프 질의는 여전히 재귀 CTE의 영역에 남습니다.

가변 길이 지원은 다음 메이저 릴리스의 1차 후보로 거론됩니다. rewriter가 재귀 CTE 또는 자기조인 반복으로 펴는 형태가 유력합니다.

다른 옵션과 비교

선택지가 늘었으니 정리해 둘 만합니다.

항목SQL/PGQ (PG19)Apache AGENeo4j
설치 방식PostgreSQL 코어PostgreSQL 확장별도 DB
쿼리 언어SQL + GRAPH_TABLEopenCypherCypher
데이터 저장기존 관계형 테이블AGE 전용 그래프 저장소네이티브 그래프
트랜잭션PostgreSQL MVCCPostgreSQL MVCC자체
가변 길이 경로미지원 (PG19 한정)지원지원
그래프 알고리즘일부풍부
성숙도신규 (코어 첫 진입)중간높음

이미 PostgreSQL에 든 데이터를 가볍게 그래프로 보고 싶다면 SQL/PGQ가 첫 후보입니다. 그래프 자체가 1급 워크로드라면 여전히 Apache AGE나 Neo4j가 더 멀리 갑니다.

언제 쓰면 좋은가

쓰기 좋은 쪽부터 짚습니다. 가장 자연스러운 건 권한/조직도 탐색입니다. “이 사용자의 상위 N단계 관리자"처럼 깊이가 정해진 질의가 여기 들어갑니다. “내가 산 상품을 산 사람이 산 다른 상품” 같은 가벼운 추천, 친구의 친구 정도로 얕은 소셜 그래프, 기존 BI 쿼리에 그래프 패턴을 끼워 넣는 분석 워크로드도 잘 맞습니다.

반대로 적합하지 않은 경우는 분명합니다. 트리 루트까지 N단계를 거슬러 오르거나 도달 가능한 모든 노드를 훑는 것처럼 깊이가 가변인 traversal, PageRank, 중심성, 커뮤니티 탐지 같은 본격 그래프 알고리즘은 이 범위를 벗어납니다. 수억 노드급 그래프도 마찬가지인데, 이쪽은 네이티브 그래프 저장소의 인덱스/캐시 구조가 더 유리합니다.

선택 기준 자체는 단순합니다. 그래프 모양 질의가 늘면 SQL/PGQ로 옮기고, 그래프 워크로드가 본진이 되는 순간 전용 엔진으로 갑니다.

마무리

PostgreSQL 19의 SQL/PGQ는 화려한 신기능이라기보다 관계형 DB가 그래프 워크로드를 흡수하는 첫 발판에 가깝습니다. 첫 릴리스는 의도적으로 좁습니다. 고정 깊이부터 안정적으로 굳히고, 가변 길이는 다음으로 미루는 그림입니다.

제가 주목하는 지점은 몇 가지예요. 표준이 코어로 들어와 Apache AGE와 SQL/PGQ가 한 데이터베이스 안에서 공존할 수 있게 됐고, 새 엔진을 들이지 않고 기존 플래너에 얹은 rewriter 기반 설계라 운영 부담도 최소이며, 가변 길이를 일단 빼고 출시한 절제 역시 신기능 폭주 대신 표준 추종을 우선한 결정으로 읽혀요.

9월 정식 출시 전 베타 단계에서 한 번쯤 만져볼 만한 기능으로, 같은 시리즈의 PostgreSQL 19 새 기능 총정리, EXPLAIN ANALYZE RDTSC, 파티션 MERGE/SPLIT도 함께 참고할 수 있어요.

참고 자료