자연어로 DB에 묻는 것의 한계 — 스키마가 답을 결정한다
같은 질문도 스키마 설계에 따라 답이 달라진다. AI 질의가 실패하는 구조적 지점.
같은 질문, 다른 답
"이번 달 매출이 얼마인가"라는 질문을 생각해보자. 답을 내려면 다음이 정해져야 한다.
- 매출은 주문 금액인가, 결제 완료 금액인가
- 취소·환불은 뺀 것인가
- '이번 달'은 주문일 기준인가 결제일 기준인가
- 세금과 배송비는 포함인가
이 정의가 스키마에 없으면 어떤 도구도 정확히 답할 수 없다. 자연어 질의의 한계는 대부분 모델이 아니라 여기서 온다.
스키마에 드러나지 않는 것들
| 규칙 | 스키마에서 보이는가 |
|---|---|
| 소프트 삭제 (deleted_at IS NULL) | 컬럼은 보이나 필터 필요성은 모름 |
| 상태 코드 의미 (status = 3) | 숫자만 보임 |
| 테넌트 분리 | 컬럼은 보이나 필수 조건인지 모름 |
| 테스트 계정 제외 | 전혀 안 보임 |
| 중복 데이터의 정본 기준 | 안 보임 |
이 중 하나만 빠져도 결과가 조용히 틀린다. 오류가 나면 알아차리지만, 숫자가 그럴듯하게 나오면 검증 없이 쓰게 된다.
개선 1 — 스키마에 주석 달기
대부분의 DB가 컬럼·테이블 주석을 지원한다.
```sql
COMMENT ON COLUMN orders.status IS
'1=대기, 2=결제완료, 3=배송중, 4=완료, 9=취소';
COMMENT ON COLUMN orders.deleted_at IS
'소프트 삭제. 모든 조회에서 IS NULL 조건 필요';
```
주석은 사람에게도 유용하고, 스키마를 읽는 도구에도 전달된다. 투자 대비 효과가 큰 작업이다.
개선 2 — 뷰로 정의를 고정
자주 쓰는 개념을 뷰로 만들어두면 정의가 한 곳에 모인다.
```sql
CREATE VIEW valid_orders AS
SELECT * FROM orders
WHERE deleted_at IS NULL
AND status IN (2, 3, 4)
AND user_id NOT IN (SELECT id FROM users WHERE is_test);
```
"매출"을 물었을 때 이 뷰를 쓰게 하면 위의 규칙들이 자동으로 적용된다. 사람이 직접 쿼리할 때도 같은 이득이 있다.
개선 3 — 용어 정의 제공
조직 안에서만 통하는 용어가 있다.
```markdown
- MAU: 해당 월에 1회 이상 로그인한 고유 사용자 (테스트 계정 제외)
- 활성 매장: 최근 30일 내 주문이 1건 이상 있는 매장
- 신규: 첫 주문일이 해당 기간 내인 사용자
```
이 정의가 없으면 같은 단어에 대해 매번 다른 쿼리가 나온다. 사람끼리도 마찬가지다.
검증 방법
생성된 결과를 그대로 믿지 않기 위한 실용적 절차:
1. SQL을 함께 본다
답만 보지 말고 어떤 쿼리로 나왔는지 확인한다. 조건절만 훑어도 대부분의 오류가 보인다.
2. 알고 있는 값과 대조
이미 아는 기간·항목으로 먼저 물어본다. 그 값이 맞으면 신뢰도가 올라간다.
3. 건수부터 확인
```
"이번 달 주문 건수는?" → 알고 있는 대략의 규모와 맞는가
```
4. 다른 각도로 재확인
합계를 물었으면 세부를 물어 합이 맞는지 본다.
적합한 용도와 아닌 용도
| 적합 | 부적합 |
|---|---|
| 탐색적 조회 (대략 파악) | 대외 보고 수치 |
| 쿼리 초안 작성 | 검증 없는 자동 실행 |
| 스키마 파악 | 정의가 모호한 지표 |
| 반복 조회의 출발점 | 금액·정산 관련 확정 계산 |
경계는 틀렸을 때의 비용으로 나눈다. 탐색 단계에서 틀리면 다시 물어보면 되지만, 정산 수치가 틀리면 되돌리기 어렵다.
최종 수정 2026-08-28