데이터 모델 기반 SQL 성능 설계: Grain·PK·관계·접근 패턴
데이터 Grain, 식별자, 관계와 이력 구조가 조인 수·중복·인덱스 후보·DML 비용을 결정하는 과정을 SQLP 튜닝 관점에서 분석합니다.
핵심 요약
SQL 성능은 문장만이 아니라 데이터 모델이 만든 행의 의미(Grain), 식별자, 관계, 이력 저장 방식에 의해 크게 좌우됩니다. 모델을 성급하게 비정규화하거나 PK 순서를 인덱스 공식처럼 정하지 말고, 업무 정합성을 지키는 논리 모델 위에서 실제 접근 패턴과 물리 설계를 함께 검증합니다.
1. Grain이 결과 행 수를 결정한다
주문 Header는 주문당 한 행, 주문상품은 상품 Line당 한 행입니다.
ORDER : order_id당 1행
ORDER_ITEM : order_id + line_no당 1행
PAYMENT : 결제 시도당 여러 행 가능
이 Grain을 모르고 세 테이블을 조인하면 결제 시도 수만큼 주문상품이 증식해 금액 합계가 부풀 수 있습니다. 튜닝 전에 각 Row Source의 한 행이 무엇을 나타내는지 적고, 필요한 수준으로 먼저 집계합니다.
SELECT o.order_id,
i.item_amount,
p.paid_amount
FROM orders o
JOIN (
SELECT order_id, SUM(quantity * unit_price) AS item_amount
FROM order_item
GROUP BY order_id
) i ON i.order_id = o.order_id
LEFT JOIN (
SELECT order_id, SUM(amount) AS paid_amount
FROM payment
WHERE status = 'SUCCESS'
GROUP BY order_id
) p ON p.order_id = o.order_id;
2. 식별자와 인덱스는 목적이 다르다
PK는 업무 행을 유일하게 식별하고 참조 무결성을 연결합니다. PK 제약을 지원하는 인덱스가 생길 수 있지만, 업무 PK 순서가 모든 검색 SQL의 최적 인덱스 순서라는 뜻은 아닙니다.
WHERE branch_code = :branch
AND trade_date >= :from_date
AND trade_date < :to_date
이 Access Path가 매우 중요하다면 (branch_code, trade_date) 인덱스를 검토할 수 있습니다. 그러나 PK를 성능만을 이유로 바꾸면 모든 FK와 업무 식별 의미에 영향이 갑니다. 필요한 조회 인덱스를 별도로 설계하는 편이 안전할 수 있습니다.
3. 관계가 조인 방식과 중복을 만든다
- 1:M 관계는 M쪽과 조인하면 1쪽 행이 반복됩니다.
- 선택 관계는 Outer Join과 NULL 처리를 요구할 수 있습니다.
- M:N 관계는 교차 엔터티로 해소하지 않으면 속성의 소속과 유일성이 불명확해집니다.
- FK가 없거나 의미가 약하면 옵티마이저뿐 아니라 애플리케이션의 정합성 검증 비용도 커집니다.
모든 관계를 식별관계로 길게 전파하거나, 반대로 업무 관계를 코드값만으로 숨기면 키 폭·조인 조건·변경 영향이 커질 수 있습니다.
4. 이력 모델이 SQL 복잡도를 결정한다
점이력
변경 시점별 행을 저장합니다.
customer_id, changed_at, status
최신 행은 ROW_NUMBER, KEEP, Index Descending Top-N 등으로 찾습니다.
선분이력
유효 시작·종료 시점을 저장합니다.
customer_id, valid_from, valid_to
특정 시점 조회와 기간 겹침 조건이 명확하지만, 종료일 갱신과 중복 기간 방지 규칙이 필요합니다.
모델 선택은 조회 SQL뿐 아니라 동시 갱신, 무결성, 데이터 보관 요구를 함께 봅니다.
5. 정규화와 물리 최적화의 순서
정규화는 중복과 갱신 이상을 줄여 업무 사실을 안정적으로 표현합니다. 반정규화·파생 컬럼·요약 테이블은 다음 조건에서만 검토합니다.
- 측정된 병목이 존재
- 원본과 파생값 동기화 규칙이 명확
- 실패·재처리·복구 경로가 있음
- 읽기 이득이 DML·저장·운영 비용보다 큼
- 결과 정합성을 자동 검산할 수 있음
실행계획과 함께 보는 순서
- 각 Row Source의 Grain과 실제
A-Rows를 적습니다. - 최초 행 증식 또는 추정 오류 지점을 찾습니다.
- 조인 전에 집계·필터링할 수 있는지 봅니다.
- PK/FK와 별도로 핵심 Access Path용 인덱스를 설계합니다.
- 모델 변경이 모든 SQL·DML·운영에 주는 영향을 회귀 검증합니다.
자주 틀리는 판단
- 등치 컬럼은 무조건 PK 앞에 둬야 한다 → PK의 식별 목적과 조회 인덱스 목적을 혼동
- 정규화는 항상 느리다 → 데이터량·접근 패턴·조인 방식에 따라 다름
- 테이블을 합치면 조인이 사라져 항상 빠르다 → 행 폭·NULL·경합·DML 비용이 증가할 수 있음
- FK는 성능에 필요 없으므로 제거한다 → 정합성과 옵티마이저 정보까지 잃을 수 있음
복습 문제
- 조인 전 각 테이블의 Grain을 적어야 하는 이유는 무엇인가?
- 업무 PK와 핵심 검색용 복합 인덱스를 분리해 설계할 수 있는 이유는 무엇인가?
- 반정규화 전에 반드시 준비해야 할 정합성 관리 항목을 설명하라.