PostgreSQL 19의 그래프 기능, 쉽게 이해하기
중년개발자
@loxo
약 6시간 전
PostgreSQL 19의 그래프 기능, 쉽게 이해하기
PostgreSQL 19에는 Property Graph(속성 그래프) 기능이 추가됩니다.
한 문장으로 정의하면 다음과 같습니다.
기존 PostgreSQL 테이블을 그대로 두고, 테이블의 행을 정점(Vertex), 테이블 사이의 관계를 간선(Edge)으로 바라보며 검색하는 기능입니다.
별도의 그래프 데이터베이스나 PostgreSQL 확장 기능 없이, 국제 SQL 표준인 SQL/PGQ(SQL Property Graph Queries) 방식으로 그래프 질의를 사용할 수 있게 된 것입니다.
다만 2026년 7월 24일 기준 PostgreSQL 19는 Beta 2 단계이며, 정식 버전은 2026년 9~10월경 출시될 예정입니다. 아직 운영 환경보다는 학습과 검증 목적으로 접근하는 것이 좋습니다. PostgreSQL 19 Beta 2 공식 발표
1. 여기서 말하는 그래프란?
차트나 통계 그래프를 말하는 것이 아닙니다.
사람, 상품, 계좌 같은 대상을 점으로 표시하고, 대상 사이의 관계를 선으로 연결한 데이터 구조입니다.
그래프 용어로 표현하면 다음과 같습니다.
| 그래프 용어 | 의미 | 일반 테이블 예 |
|---|---|---|
| Vertex / Node | 대상 또는 객체 | 고객, 상품, 계좌 |
| Edge / Relationship | 대상 사이의 관계 | 주문함, 친구임, 송금함 |
| Label | 대상이나 관계의 종류 | customer, product, transferred_to |
| Property | 대상이나 관계가 가진 값 | 고객명, 가격, 거래금액 |
예를 들어 은행 데이터라면 다음과 같이 볼 수 있습니다.
(고객A)-[보유함]->(계좌1)-[송금함]->(계좌2)<-[보유함]-(고객B)기존 SQL에서는 여러 테이블을 JOIN해야 하지만, Property Graph에서는 관계의 모양을 그대로 적어서 찾습니다.
2. PostgreSQL이 그래프 DB로 바뀐 것인가?
정확히 말하면 아닙니다.
PostgreSQL 19의 Property Graph는 Neo4j 같은 전용 그래프 저장 엔진이 아닙니다. 공식 문서에서는 이를 기존 관계형 테이블 위에 놓이는 읽기 전용 뷰와 비슷한 구조로 설명합니다.
- 데이터는 기존 테이블에 그대로 저장됩니다.
CREATE PROPERTY GRAPH가 데이터를 복사하지 않습니다.- 그래프 질의는 내부적으로 관계형 조인으로 처리됩니다.
- 일반 SQL과 그래프 질의를 한 쿼리에서 함께 사용할 수 있습니다.
- 기존 인덱스, 통계 정보, PostgreSQL 실행 계획을 그대로 이용합니다.
즉, Property Graph는 새로운 저장 방식이라기보다 다음에 가깝습니다.
기존 테이블을 그래프 관점으로 해석하는 선언과 새로운 질의 문법
PostgreSQL 19 Property Graph 공식 문서
3. 기존 테이블을 그래프로 바꾸는 방법
고객, 주문, 상품 테이블이 있다고 가정하겠습니다.
customers
- customer_id
- name
orders
- order_id
- ordered_at
products
- product_id
- name
- price
customer_orders
- customer_id
- order_id
order_items
- order_id
- product_id
- quantity이를 그래프로 바라보면 다음과 같습니다.
고객, 주문, 상품은 독립적인 대상이므로 정점이 됩니다.
customer_orders, order_items는 두 대상을 연결하는 역할이므로 간선이 됩니다.
CREATE PROPERTY GRAPH shop_graph
VERTEX TABLES (
customers KEY (customer_id)
LABEL customer
PROPERTIES (customer_id, name),
orders KEY (order_id)
LABEL "order"
PROPERTIES (order_id, ordered_at),
products KEY (product_id)
LABEL product
PROPERTIES (product_id, name, price)
)
EDGE TABLES (
customer_orders
SOURCE KEY (customer_id)
REFERENCES customers (customer_id)
DESTINATION KEY (order_id)
REFERENCES orders (order_id)
LABEL placed,
order_items
SOURCE KEY (order_id)
REFERENCES orders (order_id)
DESTINATION KEY (product_id)
REFERENCES products (product_id)
LABEL contains
PROPERTIES (quantity)
);이 명령은 새로운 그래프 데이터를 만들지 않습니다. 어떤 테이블을 정점과 간선으로 해석할지만 등록합니다.
4. 그래프를 어떻게 조회하는가?
고객이 주문한 상품을 찾는 패턴은 다음과 같습니다.
(고객)-[주문함]->(주문)-[포함함]->(상품)PostgreSQL 19에서는 이를 GRAPH_TABLE, MATCH 문법으로 표현합니다.
SELECT
result.customer_name,
result.order_id,
result.product_name,
result.quantity
FROM GRAPH_TABLE (
shop_graph
MATCH
(c IS customer)
-[p IS placed]->
(o IS "order")
-[i IS contains]->
(prd IS product)
COLUMNS (
c.name AS customer_name,
o.order_id AS order_id,
prd.name AS product_name,
i.quantity AS quantity
)
) AS result;그래프 패턴은 다음처럼 읽으면 됩니다.
(c IS customer) 고객 정점
-[p IS placed]-> 주문했다는 방향 관계
(o IS "order") 주문 정점
-[i IS contains]-> 상품을 포함한다는 관계
(prd IS product) 상품 정점GRAPH_TABLE의 결과는 일반 테이블처럼 취급할 수 있습니다. 따라서 외부에서 JOIN, WHERE, ORDER BY, 집계 함수 등을 다시 사용할 수 있습니다. PostgreSQL 19 Graph Queries 공식 문서
5. 기존 JOIN과 무엇이 다른가?
기존 SQL은 테이블을 중심으로 생각합니다.
SELECT
c.name,
o.order_id,
p.name
FROM customers c
JOIN customer_orders co
ON co.customer_id = c.customer_id
JOIN orders o
ON o.order_id = co.order_id
JOIN order_items oi
ON oi.order_id = o.order_id
JOIN products p
ON p.product_id = oi.product_id;그래프 질의는 관계의 형태를 중심으로 생각합니다.
MATCH
(c IS customer)
-[IS placed]->
(o IS "order")
-[IS contains]->
(p IS product)| 기존 SQL | Property Graph |
|---|---|
| 어떤 테이블을 조인할지 생각 | 어떤 관계를 따라갈지 생각 |
| 테이블과 FK 조건 중심 | 정점과 간선 패턴 중심 |
| 정형화된 집계에 강함 | 연결 관계 탐색에 읽기 쉬움 |
| 긴 다중 JOIN이 발생 | 관계를 그림처럼 표현 |
성능이 자동으로 빨라지는 기능은 아닙니다. 그래프 패턴 역시 내부적으로는 기존 테이블의 조인으로 실행됩니다.
따라서 그래프 질의가 느리다면 기존 SQL과 마찬가지로 다음을 확인해야 합니다.
- 간선 테이블의 출발점·도착점 컬럼 인덱스
- 기본키와 외래키
EXPLAIN (ANALYZE, BUFFERS)- 통계 정보와 데이터 분포
- 불필요하게 넓은 탐색 범위
6. 어디에 유용한가?
연결 자체가 중요한 데이터에 적합합니다.
금융 이상거래 탐지
고객 → 계좌 → 송금 → 계좌 → 고객- 여러 계좌를 거쳐 자금이 순환하는 패턴
- 하나의 기기에서 여러 명의 계좌로 로그인한 관계
- 동일 전화번호·주소·기기를 공유하는 고객 집단
- 특정 계좌를 중심으로 연결된 거래 상대방
추천 시스템
사용자 → 구매 → 상품 → 카테고리 ← 상품 ← 구매 ← 다른 사용자- 같은 상품을 구매한 사용자
- 사용자가 자주 구매한 카테고리
- 유사 사용자가 구매한 다른 상품
조직과 권한 분석
사용자 → 소속 조직 → 역할 → 접근 권한 → 시스템- 특정 사용자가 접근 가능한 시스템
- 과도한 권한을 가진 사용자
- 역할을 여러 번 상속받아 생긴 간접 권한
SNS·커뮤니티
회원 → 팔로우 → 회원 → 작성 → 게시물- 친구의 친구
- 공통 팔로워
- 특정 사용자 주변의 연결 집단
지식 그래프와 AI/RAG
문서 → 언급 → 회사 → 개발 → 제품 → 사용 → 기술문서 청크만 벡터 검색하는 방식에 관계 탐색을 더할 수 있습니다. 다만 PostgreSQL 19 Property Graph 자체가 벡터 검색이나 GraphRAG 전체 기능을 제공하는 것은 아닙니다. pgvector, 임베딩 생성, 검색 로직은 별도로 필요합니다.
7. 모델링할 때 가장 중요한 기준
독립적으로 의미가 있는 데이터는 정점
다음과 같은 데이터는 보통 정점이 적합합니다.
- 고객
- 계좌
- 상품
- 주문
- 게시물
- 회사
두 대상을 연결하는 것이 주목적이면 간선
다음과 같은 연결 테이블은 간선에 적합합니다.
- 친구 관계
- 팔로우
- 고객과 주문 연결
- 주문과 상품 연결
- 사용자와 역할 연결
사건 자체가 중요하면 정점으로 만들기
은행 거래를 단순히 다음과 같이 만들 수도 있습니다.
(출금계좌)-[송금 10만원]->(입금계좌)그러나 거래에 승인 상태, 환율, 채널, 시간, 지급사유코드 등 많은 정보가 있고 거래 자체를 분석해야 한다면 거래를 정점으로 두는 편이 자연스럽습니다.
(출금계좌)-[출금]->(거래)-[입금]->(입금계좌)판단 기준은 간단합니다.
관계가 중요한가, 아니면 사건 자체가 중요한가?
관계가 중요하면 간선, 사건의 속성과 생명주기가 중요하면 정점으로 설계합니다.
8. 알아두면 유용한 실전 팁
① ID를 검색하려면 Property에 명시하기
KEY는 정점의 식별자이지만 자동으로 조회 가능한 속성이 되는 것은 아닙니다. 명시적인 PROPERTIES 목록을 사용한다면 검색하거나 반환할 ID도 포함해야 합니다.
KEY (customer_id)
PROPERTIES (customer_id, name)② 간선 테이블의 양쪽 컬럼에 인덱스 만들기
CREATE INDEX idx_customer_orders_customer
ON customer_orders (customer_id);
CREATE INDEX idx_customer_orders_order
ON customer_orders (order_id);그래프 질의도 결국 조인을 수행하므로 연결 컬럼의 인덱스가 중요합니다.
③ 방향을 업무 의미에 맞게 정하기
(고객)-[소유함]->(계좌)처럼 자연스럽게 읽히도록 Source와 Destination을 정의하면 쿼리가 훨씬 이해하기 쉬워집니다. 질의할 때는 정방향, 역방향, 양방향 모두 표현할 수 있습니다.
-- 정방향
(customer)-[owns]->(account)
-- 역방향
(account)<-[owns]-(customer)
-- 양방향
(person)-[friend]-(person)④ Label은 명사와 동사로 구별하기
- 정점:
customer,account,product - 간선:
owns,transferred_to,contains
이렇게 하면 MATCH가 문장처럼 읽힙니다.
⑤ EXPLAIN으로 실제 실행 계획 확인하기
EXPLAIN (ANALYZE, BUFFERS)
SELECT *
FROM GRAPH_TABLE (
shop_graph
MATCH ...
COLUMNS (...)
) AS g;그래프 문법만 보고 전용 그래프 탐색 엔진이 동작한다고 생각하면 안 됩니다. 실제로 어떤 조인과 스캔이 발생하는지 확인해야 합니다.
⑥ 그래프와 일반 SQL을 섞어서 사용하기
GRAPH_TABLE 결과를 일반 테이블처럼 사용할 수 있다는 점이 PostgreSQL 방식의 큰 장점입니다.
SELECT
g.product_name,
SUM(g.quantity) AS total_quantity
FROM GRAPH_TABLE (
shop_graph
MATCH
(c IS customer)
-[IS placed]->
(o IS "order")
-[i IS contains]->
(p IS product)
COLUMNS (
p.name AS product_name,
i.quantity AS quantity
)
) AS g
GROUP BY g.product_name
ORDER BY total_quantity DESC;그래프는 관계를 찾고, 일반 SQL은 집계와 정렬을 담당하도록 나누면 좋습니다.
9. 현재 PostgreSQL 19의 중요한 한계
가장 큰 제한은 가변 길이 경로 탐색을 아직 지원하지 않는다는 점입니다.
예를 들어 다음과 같은 질문입니다.
친구 관계를 1~3단계 따라가라
연결이 끝날 때까지 계속 탐색하라
A에서 B까지 가능한 경로를 찾아라성숙한 그래프 질의 언어에서는 간선 반복 횟수를 지정할 수 있지만, 현재 PostgreSQL 19 구현에서는 각 단계를 직접 적어야 합니다.
-- 2단계 관계는 2개의 간선을 직접 작성
MATCH
(a IS person)
-[IS friend]->
(b IS person)
-[IS friend]->
(c IS person)깊이를 알 수 없는 계층이나 네트워크를 탐색하려면 기존 방식인 WITH RECURSIVE를 사용해야 합니다.
이 때문에 PostgreSQL 19 Property Graph는 현재 다음 용도에 더 적합합니다.
- 깊이가 정해진 관계 패턴
- 긴 JOIN을 이해하기 쉽게 표현
- 기존 관계형 데이터에 그래프 관점 추가
- SQL 집계와 관계 탐색의 결합
반대로 다음 용도에는 아직 전용 그래프 DB가 더 적합할 수 있습니다.
- 깊이가 불명확한 다단계 탐색
- 최단 경로 계산
- 매우 큰 네트워크의 반복 순회
- 그래프 알고리즘 중심의 서비스
- 실시간으로 수십 단계 관계를 탐색하는 시스템
참고 글에서도 이 가변 길이 경로 미지원 문제를 핵심 한계로 지적하고 있습니다. Understanding Postgres 19 Property Graphs
10. PostgreSQL 19 그래프의 핵심 결론
PostgreSQL 19의 Property Graph는 PostgreSQL을 완전히 새로운 그래프 데이터베이스로 바꾸는 기능이 아닙니다.
기존 관계형 테이블을 정점과 간선으로 선언하고, 복잡한 JOIN을 관계 패턴 형태로 표현할 수 있게 만든 SQL 표준 기능입니다.
따라서 가장 좋은 사용 방식은 다음과 같습니다.
- 기존 PostgreSQL 데이터를 그대로 유지한다.
- 관계가 중요한 일부 영역만 Property Graph로 선언한다.
- 고정된 깊이의 관계는
MATCH로 조회한다. - 집계와 정렬은 일반 SQL로 처리한다.
- 깊이가 불명확한 탐색은 재귀 CTE를 사용한다.
- 전용 그래프 알고리즘이 핵심이라면 Neo4j·Memgraph·Apache AGE 등과 비교한다.
현재 단계에서 가장 정확한 평가는 이렇습니다.
“PostgreSQL 안에 그래프 DB가 들어왔다”기보다는, “PostgreSQL이 기존 테이블을 그래프 언어로 읽는 방법을 갖게 됐다”에 가깝습니다.