안녕하세요! 오늘은 최근 데이터베이스 트렌드가 어떻게 달라지고 있는지, 그리고 그 변화를 PostgreSQL의 pgvector를 활용해 어떻게 풀어낼 수 있는지 제가 이해한 만큼 간단한 예시로 정리해 보려고 합니다.
과거에는 데이터 유형이나 검색 방식에 따라 별도의 검색 엔진이나 데이터베이스를 따로 두고 조합하는 경우가 많았습니다. 그런데 최근에는 범용 DB가 전문검색(Full-text), 벡터 유사도 검색, 그래프 탐색, JSON 처리 같은 기능을 자체 엔진 안으로 흡수하는 방향으로 발전하고 있습니다. 데이터 이동 비용을 줄이고, 한 번의 쿼리에서 관계형 조건과 벡터 검색을 함께 처리하려는 흐름이 강해진 셈입니다.
여기서 중요한 점은 "AI가 모든 작업을 수행하지 않아도 된다"는 점입니다. 반복적이고 규칙적인 검색과 필터링은 데이터가 있는 DB 쪽으로 내려보내고, LLM은 질문 해석이나 파라미터 추출 같은 상위 추론에 집중하도록 역할을 나눌 수 있습니다.
1. 최근 DB 트렌드 변화의 핵심
최근 데이터베이스 엔진들이 흡수하고 있는 주요 흐름을 꼽아보면 다음과 같습니다.
- 벡터 검색: 임베딩 또는 수치 feature vector를 DB에 저장하고 유사한 데이터를 검색
- Hybrid Search: 키워드 검색(BM25/Full-text)과 벡터 유사도 검색을 결합
- Graph 탐색: 데이터 간의 관계를 노드와 엣지 구조로 탐색
- JSON·문서형 데이터: 정형 스키마와 유연한 비정형 구조를 한 DB에서 통합 관리
- AI Retrieval의 DB 내부화: 검색, 필터링, 유사도 계산을 애플리케이션이나 외부 엔진이 아닌 DB 엔진 내부에서 직접 수행
2. PostgreSQL pgvector를 활용한 3가지 예시
이 중 벡터 검색은 PostgreSQL의 pgvector 확장을 통해 간단한 예시로 바로 확인해볼 수 있습니다. 기존 정형 테이블에 벡터 컬럼을 두고, SQL 조건과 벡터 거리 연산을 결합하는 대표적인 3가지 예시를 정리해 보았습니다.
예시 1: 운영 지표를 feature vector로 만들어 유사 사례 찾기
임베딩 모델을 거치지 않고, 도메인 지식상 중요하다고 판단한 수치 지표(KPI)들을 모아 하나의 벡터로 구성하는 방식입니다. 특정 시점이나 운영 개체의 "상태 지문(fingerprint)"처럼 활용할 수 있습니다.
[전환율, 취소율, 응답 성공률, 신규 사용자 비율, 유입 채널 비율]
↓ 정규화 / 스케일링
[-0.82, 0.91, -1.05, 0.30, 1.18]
↓
feature_vector 컬럼에 저장
예를 들어 일단위 서비스 운영 상태를 비교한다고 가정하면 다음과 같은 스키마를 구성할 수 있습니다.
daily_metrics
- date
- unit_id
- conversion_rate
- cancel_rate
- response_rate
- new_user_ratio
- channel_ratio
- feature_vector vector(5)
오늘의 지표 벡터가 [-0.80, 0.88, -1.10, 0.25, 1.20]으로 계산되었다면, pgvector 거리 연산자(<->)를 사용해 오늘과 운영 패턴이 가장 유사했던 과거 날짜 5건을 바로 조회할 수 있습니다.
SELECT date, unit_id,
feature_vector <-> :target_vector AS distance
FROM daily_metrics
WHERE date < CURRENT_DATE
ORDER BY feature_vector <-> :target_vector
LIMIT 5;
이 방식의 가장 큰 장점은 SQL 결합력입니다. 벡터 검색으로 찾은 유사 행에 당시의 운영 로그, 장애 메모, 이슈 텍스트 테이블을 JOIN하면, "과거에 오늘과 지표 패턴이 비슷했던 날이 언제였고, 당시 어떤 원인과 조치가 있었는지"를 한 번의 쿼리로 연결해 볼 수 있습니다.
예시 2: 비정상 패턴 골라내기 (이상치 탐지)
벡터 거리 연산은 가장 가까운 데이터를 찾는 검색뿐만 아니라, 정상 패턴에서 거리가 너무 먼 데이터(Outlier)를 걸러내는 데에도 쓸 수 있습니다. 대표적인 예가 비정상 거래(FDS)나 장애 징후 탐지입니다.
사용자의 평소 정상 이용 패턴이나 서버의 정상 상태를 하나의 기준 벡터(프로파일)로 만들어 두고, 새로 들어온 이벤트와의 거리를 계산합니다. 기준 거리(임계값)를 초과하면 이상 패턴으로 간주하는 식입니다.
-- 정상 프로파일과의 거리가 임계값(0.8)보다 먼 비정상 거래 필터링
SELECT tx_id, user_id, amount,
profile_vector <-> tx_vector AS anomaly_score
FROM transactions
WHERE profile_vector <-> tx_vector > 0.8
AND created_at >= NOW() - INTERVAL '1 hour';
별도의 머신러닝 탐지 엔진을 복잡하게 거치지 않고도, "최근 1시간 내 거래 중(WHERE) 정상 범위와 거리가 먼 것(>)"처럼 일반 SQL 조건과 결합해 실시간으로 후보를 추려낼 수 있습니다.
예시 3: 텍스트 임베딩으로 복합 뉘앙스 검색하기 (WHERE 조건의 한계 극복)
문장이나 문서를 임베딩 모델에 넣어 고차원 숫자 벡터로 변환한 뒤 vector 컬럼에 저장하면, 의미 기반 검색뿐만 아니라 엄격한 SQL WHERE 조건의 한계를 보완할 수 있습니다.
전통적인 SQL WHERE 조건은 참/거짓이 명확한 필터링에는 좋지만, 여러 조건이 얽힌 정성적인 검색에서는 한계가 드러납니다. 예를 들어 "주말에 노트북 들고 가기 좋은 조용한 근교 대형 카페"를 기존 SQL로 찾으려면 테이블에 수많은 컬럼이나 태그가 미리 정의되어 있어야 합니다.
SELECT * FROM cafes
WHERE city IN ('경기', '인천')
AND has_parking = true
AND has_power_socket = true
AND noise_level = 'low'
AND capacity >= 50;
이 방식은 치명적인 단점이 있습니다.
- 태그 누락: 콘센트 여부를 미입력했거나,
noise_level같은 주관적 컬럼이 없으면 검색 대상에서 누락됩니다. - 0건 결과 (Zero-Result): 5개 조건 중 단 하나만 어긋나도 결과가 0건이 되어버립니다.
반면 카페의 소개글, 메뉴, 그리고 방문자 리뷰 전체를 텍스트 임베딩으로 만들어 두면 훨씬 유연해집니다. 사용자가 검색한 문장("주말에 노트북 들고 가기 좋은...")과 리뷰 임베딩 간의 거리를 비교하는 방식입니다.
비록 콘센트 태그가 없더라도 리뷰에 "자리마다 충전기가 있어서 작업하기 편했어요", "주말에 차 타고 갔는데 넓어서 조용히 쉬다 옴" 같은 뉘앙스가 녹아 있다면 높은 유사도로 잡힙니다. 또한 모든 조건을 100% 만족하지 않더라도 가장 근접한 차선책들을 순서대로 추천해주기 때문에 결과가 0건으로 끝나는 문제를 피할 수 있습니다.
실제로 구현한다면, 엄격한 조건(영업 중, 반경 30km 이내)은 기존 WHERE 절로 단단하게 자르고, 분위기나 취향 같은 뉘앙스는 임베딩 거리로 정렬하는 Hard Filter + Soft Matching 결합 형태로 활용하는게 좋습니다.
SELECT id, name,
cafe_vector <-> :query_vector AS similarity_rank
FROM cafes
WHERE is_open = true -- 엄격한 조건 (Hard)
AND distance_km <= 30 -- 엄격한 조건 (Hard)
ORDER BY cafe_vector <-> :query_vector -- 유연한 뉘앙스 정렬 (Soft)
LIMIT 10;
3. 벡터 기준이 고정되기 전에는 Python에서 먼저 검증하기
앞서 소개한 3가지 예시 모두, DB에 컬럼을 파고 인덱스를 걸기 전에 반드시 거쳐야 할 공통 과정이 있습니다. 바로 "무엇을 기준으로 벡터 공간을 정의할 것인가"를 검증하는 일입니다.
이 기준이 아직 확정되지 않은 상태에서 곧바로 DB 스키마부터 만들면 수정 비용이 매우 커집니다. 따라서 Python 환경에서 가볍고 빠르게 반복 실험하는 편이 훨씬 유리합니다. 각 예시별로 Python에서 먼저 확인해야 할 핵심 질문은 다음과 같습니다.
- 예시 1 (수치 지표): "어떤 KPI 지표들을 조합하고 어떤 스케일러를 써야 실제로 비슷한 운영 패턴이 잡히는가?"
- 예시 2 (이상치 탐지): "거리 임계값(Threshold)을 얼마로 설정해야 정상 거래를 이상 거래로 오탐하지 않는가?"
- 예시 3 (복합 뉘앙스): "어떤 임베딩 모델과 청킹(자르기) 크기를 써야 도메인 검색 품질이 가장 좋은가?"
수치 feature vector(예시 1)를 예로 들면, 다음과 같이 Python에서 기준을 좁혀가는 과정을 거치게 됩니다.
PostgreSQL 원본 데이터
↓
Python / pandas
↓
feature 후보 조합 선택
↓
스케일링 방식 변경 (Standard vs MinMax)
↓
거리 척도 비교 (L2 vs Cosine)
↓
유사 사례 결과 검토 ──(패턴 불일치 시 재조정)──↺
처음에는 직관적인 3개 기본 지표로 시작해볼 수 있습니다.
features = [
"conversion_rate",
"cancel_rate",
"response_rate"
]
추출된 유사 사례가 실제 운영 맥락을 충분히 대변하지 못한다면, 비율 지표를 추가하거나 가중치를 조정하면서 실험을 이어갑니다.
features = [
"conversion_rate",
"cancel_rate",
"response_rate",
"new_user_ratio",
"channel_ratio"
]
4. 운영 단계에서 벡터 규격을 반드시 고정해야 하는 이유
벡터 간의 거리를 측정하려면 비교 대상이 되는 모든 행이 동일한 차원 수, 동일한 기준, 동일한 모델(또는 스케일)로 생성되어야 합니다. 과거 데이터와 현재 데이터의 생성 기준이 어긋나면 계산된 거리 값은 수학적으로 완전히 무의미해집니다.
실제 DB에 적재해 운영하기 전에 반드시 고정해야 하는 규격은 다음과 같습니다.
- 수치 벡터의 경우: 피처 목록과 순서, 스케일링 파라미터(평균·분산 등), 결측치/이상치 처리 규칙
- 텍스트 임베딩의 경우: 임베딩 모델 종류 및 고정 버전, 텍스트 전처리 및 청킹 규칙
- 공통: 거리 함수 (L2, Cosine, Inner Product 등), 이상 판별 임계값
따라서 운영 환경에서는 벡터 생성 로직을 엄격하게 버전 단위로 관리해야 합니다. 피처 조합을 바꾸거나 임베딩 모델을 신규 버전으로 업그레이드하는 경우, 기존 컬럼을 덮어쓰기보다 vector_v2처럼 새 컬럼을 정의하고 과거 데이터 전체를 동일한 신규 기준으로 재계산(backfill)해 주어야 안전합니다.
5. 실적용 과정(안)
정리해 보면 3가지 예시 모두 다음과 같은 단계로 진행하는 것이 안전합니다.
- 원본 데이터 수집: RDBMS에 정형 데이터, 로그, 텍스트 적재
- Python에서 가설 검증: 피처 조합, 임베딩 모델 평가, 이상치 임계값 튜닝
- 결과 정성 검토: 도메인 담당자가 유사 사례 및 검색 결과의 타당성 확인
- 반복 튜닝: 스케일러 조정, 청킹 단위 변경, 거리 함수 최적화
- 규격 확정 및 버전화: 파이프라인과 모델/스케일러 규격 고정
- PostgreSQL 적재: pgvector 컬럼에 일괄 적재 및 실시간/배치 생성
- 운영 쿼리 연동: HNSW / IVFFlat 인덱스 생성 + SQL 필터링/JOIN 조합
Python은 가설 검증과 빠른 실험에 강하고, pgvector는 확정된 로직을 안정적으로 서빙하고 기존 비즈니스 데이터와 결합하는 데 강합니다. DB 트렌드가 다양한 검색을 안으로 흡수하고 있다고 해서 처음부터 DB에 모든 것을 얹기보다는, Python에서 실험을 거쳐 규격을 굳힌 뒤 DB로 내려보내는 분업이 실무에서 훨씬 안정적이었습니다.
적용 단계 판단 기준
- Python에서 진행:
- 어떤 feature나 임베딩 모델을 쓸지 계속 비교·테스트 중일 때
- 유사도 기준(거리 척도, 이상치 임계값) 자체를 튜닝하고 있을 때
- PostgreSQL (pgvector)로 전환:
- 고정된 벡터 규격으로 반복 조회가 필요할 때
WHERE절의 일반 관계형 조건과 유사도 정렬을 동시에 걸어야 할 때- 대량 데이터에서 인덱스(HNSW 등) 기반 Top-K 빠른 검색이 필요할 때
- 검색된 결과에 상세 메타데이터나 업무 로그 텍스트를 바로 JOIN해야 할 때
마무리
DB 트렌드가 검색, 벡터, 그래프를 엔진 내부로 흡수하면서 아키텍처는 점점 단순해지고 표현력은 풍부해지고 있습니다. 수치 지표 기반 유사 사례 검색부터 이상치 탐지, 그리고 기존 WHERE 조건의 한계를 넘는 뉘앙스 검색까지 DB가 담당할 수 있는 영역도 넓어지고 있습니다. 앞으로 어떻게 더 진화할지 기대가 됩니다.
읽어주셔서 감사합니다.