핵심 인사이트 (3줄 요약)
- 본질: 선택도 (Selectivity)는 조건이 전체 행 중 몇 퍼센트를 남기는지, 기수성 (Cardinality)은 컬럼 값의 서로 다른 개수, 분포도 (Distribution)는 그 값들이 고르게 퍼졌는지 치우쳤는지를 보여 주는 통계 축이다.
- 가치: 비용 기반 옵티마이저 (CBO, Cost-Based Optimizer)는 이 세 축으로 결과 건수와 입출력 (I/O, Input/Output) 비용을 추정해 인덱스 스캔, 풀 테이블 스캔, 조인 순서를 결정한다.
- 판단 포인트: 높은 기수성 컬럼이라도 범위 조회가 넓으면 인덱스가 불리할 수 있고, 낮은 기수성 컬럼이라도 값 쏠림이 심하면 히스토그램 (Histogram) 없이는 잘못된 실행 계획이 나올 수 있다.
Ⅰ. 개요 및 필요성
선택도, 기수성, 분포도는 데이터베이스가 "이 조건으로 몇 행이 나올 것인가"를 추정하기 위해 가장 먼저 보는 통계 정보다. 튜닝 실무에서는 셋이 따로 노는 개념이 아니라, 기수성이 선택도의 출발점을 만들고, 분포도가 그 평균값을 교정하는 구조로 이해해야 한다.
예를 들어 회원 테이블 1,000만 건에서 customer_id = 8273151은 보통 1건만 찾으므로 선택도가 매우 낮다. 반면 gender = 'F'는 절반 가까운 행을 건드릴 수 있어 선택도가 높다. 같은 인덱스라도 전자는 소수 행을 정확히 찍는 도구가 되지만, 후자는 인덱스를 따라간 뒤 다시 수백만 행을 읽어야 하므로 오히려 비효율적일 수 있다.
또 하나 주의할 점은 기수성 (Cardinality) 이라는 말이 문맥에 따라 달라진다는 것이다. 컬럼 통계에서는 보통 "서로 다른 값의 개수"를 뜻하지만, 실행 계획 화면에서는 어떤 연산이 반환할 것으로 예상한 "행 수"를 cardinality estimate라고 부르기도 한다. 이 문서에서는 먼저 컬럼 기수성 = distinct value 개수를 중심으로 설명하고, 필요할 때 행 수 추정과 연결해 해석한다.
이 그림은 왜 세 지표를 함께 봐야 하는지를 보여 준다.
┌──────────────────────────────────────────────────────────────────────┐
│ Column stats are not decoration; they decide the path │
├──────────────────────────────────────────────────────────────────────┤
│ Query A : WHERE customer_id = 8273151 │
│ NDV high -> selectivity tiny -> index seek is natural │
│ │
│ Query B : WHERE gender = 'F' │
│ NDV low -> selectivity wide -> full scan may be cheaper │
│ │
│ Query C : WHERE grade = 'VIP' │
│ NDV low + skewed distribution -> histogram can flip the answer │
└──────────────────────────────────────────────────────────────────────┘
같은 "인덱스가 있느냐"보다 더 중요한 질문은 "그 인덱스로 찾은 뒤 실제로 얼마나 많은 행과 블록을 읽게 되느냐"다. 그래서 튜닝은 인덱스 개수 경쟁이 아니라, 통계의 질과 해석의 문제다.
- 📢 섹션 요약 비유: 사서가 책을 찾을 때 "책 종류가 몇 개인지"만 보는 것이 아니라, "이번에 몇 권을 꺼내야 하는지"와 "그 책들이 한 칸에 몰려 있는지"까지 같이 봐야 가장 빠른 동선을 고를 수 있는 것과 같다.
Ⅱ. 아키텍처 및 핵심 원리
비용 기반 옵티마이저는 테이블 행 수, 컬럼 기수성, 분포도, 히스토그램, 상관관계 통계를 조합해 결과 건수를 추정한다. 단순한 동등 조건이라면 보통 선택도 ≈ 1 / 기수성 이라는 균등 분포 가정을 출발점으로 삼고, 예상 행 수는 전체 행 수 × 선택도로 계산한다. 그러나 실제 운영 데이터는 균등하지 않기 때문에, 평균값만 믿으면 바로 오판이 생긴다.
| 통계 요소 | 무엇을 뜻하는가 | 옵티마이저가 보는 이유 |
|---|---|---|
| 전체 행 수 (Num Rows) | 테이블 규모 | 결과 건수와 전체 스캔 비용의 기준점 |
| 기수성 (NDV, Number of Distinct Values) | 서로 다른 값의 개수 | 동등 조건 선택도 계산의 출발점 |
| 분포도 (Distribution) | 값의 빈도 편차 | 평균 가정이 맞는지 검증 |
| 히스토그램 (Histogram) | 구간/값별 빈도 상세 통계 | 쏠린 값에 대한 정밀 추정 |
| 컬럼 그룹 통계 (Extended Statistics) | 컬럼 간 상관관계 | 독립 가정으로 인한 오차 보정 |
예를 들어 grade 컬럼의 값이 VIP, NORMAL, DORMANT 세 개라면 기수성만 보면 선택도는 평균 33.3%로 보인다. 하지만 실제 데이터가 VIP 0.2% / NORMAL 97% / DORMANT 2.8%라면, grade = 'VIP' 쿼리는 평균이 아니라 희소값 조회로 취급해야 한다. 이때 히스토그램이 없으면 옵티마이저는 VIP를 과대평가해 풀 스캔을 선택할 수 있고, 히스토그램이 있으면 인덱스 스캔으로 뒤집을 수 있다.
아래 흐름은 옵티마이저가 평균 가정에서 정밀 가정으로 이동하는 과정을 보여 준다.
┌──────────────────────────────────────────────────────────────────────┐
│ Predicate -> row estimate -> access path selection │
├──────────────────────────────────────────────────────────────────────┤
│ WHERE grade = 'VIP' │
│ │ │
│ ├─ NDV only -> 1 / 3 = 33.3% -> Full Scan candidate │
│ ├─ Histogram found -> actual = 0.2% -> Index Scan candidate │
│ └─ Same column, different value can yield a different best path │
└──────────────────────────────────────────────────────────────────────┘
실무에서 더 어려운 부분은 다중 조건이다. city = 'Seoul' AND district = 'Gangnam' 처럼 서로 상관된 컬럼을 독립이라고 가정하면 예상 행 수가 실제와 크게 달라질 수 있다. 그래서 최신 데이터베이스는 컬럼 그룹 통계, 동적 샘플링, 적응형 계획 같은 보정 장치를 둔다.
결국 핵심 원리는 단순하다. 기수성은 평균을 만들고, 분포도는 평균의 거짓말을 드러내며, 선택도는 최종적으로 접근 경로를 바꾸는 숫자다. 이 셋이 틀리면 조인 순서, 조인 방식, 액세스 패스가 줄줄이 흔들린다.
- 📢 섹션 요약 비유: 학교 급식실이 학생 수만 보고 줄 길이를 예측하면 틀릴 수 있지만, 반별 식사 시간표와 선호 메뉴 분포까지 알면 어느 창구를 먼저 열지 더 정확히 결정할 수 있는 것과 같다.
Ⅲ. 비교 및 연결
세 지표를 헷갈리지 않으려면 "무엇을 세는가"를 분리해서 봐야 한다. 기수성은 컬럼의 다양성, 선택도는 조건의 폭, 분포도는 값의 치우침을 설명한다. 셋을 섞어 쓰면 "기수성이 높으니 무조건 인덱스" 같은 단순화 오류가 생긴다.
| 비교 축 | 기수성 (Cardinality) | 선택도 (Selectivity) | 분포도 (Distribution) |
|---|---|---|---|
| 질문 | 값 종류가 몇 개인가 | 조건이 몇 %를 남기는가 | 특정 값이 고르게 퍼졌는가 |
| 대표 예 | 주민번호, 이메일은 높음 | customer_id = ? 는 낮음 | VIP만 극소수면 치우침 큼 |
| 인덱스 판단 영향 | 동등 조건의 평균 선택도에 영향 | 직접적으로 액세스 경로 결정 | 평균 가정의 오차를 수정 |
| 대표 함정 | 범위 조회 폭을 설명 못함 | 값별 편차를 설명 못함 | 통계 없으면 희소값을 놓침 |
이 셋은 다른 물리 통계와도 연결된다. 예를 들어 선택도가 좋아도 클러스터링 팩터 (Clustering Factor)가 나쁘면 인덱스를 타고 읽은 행이 디스크 곳곳에 흩어져 있어 기대만큼 빠르지 않을 수 있다. 반대로 선택도가 다소 높아도 커버링 인덱스 (Covering Index)로 테이블 접근을 생략하면 여전히 유리할 수 있다.
또한 바인드 변수 (Bind Variable) 사용 패턴도 결과에 영향을 준다. 값 자체를 모른 채 평균 선택도로 계획을 공유하면, grade = 'VIP'와 grade = 'NORMAL'이 같은 실행 계획을 쓰면서 성능 편차가 커질 수 있다. 그래서 일부 엔진은 바인드 피킹 (Bind Peeking), 적응형 커서 공유, SQL 플랜 관리로 이 문제를 보완한다.
즉, 선택도/기수성/분포도는 인덱스 생성 여부만 결정하는 지표가 아니다. 통계 정확도, 데이터 배치 특성, 바인딩 방식, 조인 구조를 함께 해석하는 출발점이다.
- 📢 섹션 요약 비유: 손님이 몇 종류인지, 이번 예약에 몇 명이 오는지, 특정 시간대에 몰리는지까지 따로 봐야 식당이 좌석 배치를 제대로 할 수 있는 것과 같다.
Ⅳ. 실무 적용 및 기술사 판단
실무에서 가장 흔한 사례는 상태 코드나 회원 등급처럼 "종류는 적지만 특정 값만 희소한 컬럼"이다. 예를 들어 주문 테이블 5,000만 건에서 status = 'FAILED'가 0.3%, status = 'DONE'가 96%라면, 같은 인덱스라도 실패 주문 조회와 완료 주문 조회의 최적 경로는 달라져야 한다. 이때 히스토그램 없이 평균 25%로 계산하면 두 쿼리 모두 애매한 계획으로 수렴할 수 있다.
기술사 판단 체크리스트
- 통계 정보가 대량 적재·삭제 이후 최신 상태인가?
- 낮은 선택도 인덱스를 만들기 전에 실제 조회 비율과 블록 접근 비용을 확인했는가?
- 값 쏠림이 심한 컬럼에 히스토그램을 수집했는가?
- 여러 조건이 같이 쓰일 때 컬럼 독립 가정이 깨지지 않는가?
- 범위 조회라면 선택도뿐 아니라 클러스터링 팩터와 커버링 가능성까지 봤는가?
채택 / 회피 판단
- 채택: 고기수성 동등 조건, 희소값 조회, 잘 관리된 히스토그램 기반 조건, 커버링 가능한 인덱스
- 회피 또는 보완: 대량 범위 조회, 낮은 기수성 컬럼 단독 인덱스, 통계가 오래된 테이블, 상관관계가 강한 다중 조건
자주 나오는 안티패턴
status,gender,Y/N컬럼에 "자주 조회한다"는 이유만으로 단독 인덱스를 남발하는 경우- 통계 문제를 확인하지 않고 힌트 (Hint)로 실행 계획을 고정하는 경우
- 히스토그램을 무분별하게 생성해 계획 변동성을 키우는 경우
- 기수성이 높다는 이유만으로 넓은 날짜 범위 조회에도 인덱스를 고집하는 경우
실무 판단의 핵심은 "몇 건 찾느냐"보다 "그 몇 건이 실제로 얼마나 비싸게 읽히느냐"다. 그래서 5~10% 같은 임계값은 참고선일 뿐 절대 법칙이 아니다. 저장장치 특성, 행 길이, 버퍼 캐시, 클러스터링 팩터에 따라 손익분기점은 달라진다.
- 📢 섹션 요약 비유: 지도에서 목적지가 가깝게 보여도 차가 막히면 돌아가는 길이 더 빠르듯, 데이터베이스도 선택도 숫자 하나만 보고 길을 정하면 실제 비용을 놓칠 수 있다.
Ⅴ. 기대효과 및 결론
선택도, 기수성, 분포도를 정확히 이해하면 "왜 이 쿼리는 인덱스를 안 탔는가" 또는 "왜 같은 SQL이 값에 따라 갑자기 느려졌는가"를 통계 관점에서 설명할 수 있다. 이는 단순한 성능 개선을 넘어, 실행 계획의 일관성 확보와 장애 원인 분석 속도 향상으로 이어진다.
물론 한계도 분명하다. 데이터는 계속 변하고, 통계는 샘플 기반이며, 상관관계와 바인드 변수는 여전히 오차를 만든다. 따라서 이 세 지표는 만능 답안이 아니라, 옵티마이저가 세상을 어떻게 오해할 수 있는지 보여 주는 기준 좌표로 보는 것이 정확하다.
결론적으로 이 주제는 "인덱스가 좋으냐 나쁘냐"를 가르는 문제가 아니다. 평균값으로 세상을 본 옵티마이저를, 실제 데이터 분포에 더 가깝게 교정하는 일이 핵심이다. 좋은 튜닝은 힌트보다 통계에서 먼저 시작된다.
- 📢 섹션 요약 비유: 날씨 앱이 연평균 기온만 보여 주면 오늘 옷차림을 망치기 쉽듯, 데이터베이스도 평균 통계만 보면 오늘 쿼리에 맞는 계획을 놓치기 쉽다.
📌 관련 개념 맵
| 개념 | 연결 포인트 |
|---|---|
| 비용 기반 옵티마이저 (CBO, Cost-Based Optimizer) | 선택도와 예상 행 수를 바탕으로 액세스 경로를 결정 |
| 히스토그램 (Histogram) | 치우친 분포를 평균값 대신 값별 빈도로 표현 |
| 클러스터링 팩터 (Clustering Factor) | 선택도가 좋아도 실제 블록 접근 비용이 높은지 판단 |
| 컬럼 그룹 통계 (Extended Statistics) | 다중 조건의 상관관계를 반영해 추정 오차를 줄임 |
| 바인드 피킹 (Bind Peeking) | 값 미노출로 인한 평균 계획 문제를 완화하는 기법 |
📈 관련 키워드 및 발전 흐름도
Rule-based tuning
│
▼
CBO (Cost-Based Optimizer)
│
├─ NDV / Density -> selectivity estimate
├─ Histogram -> skew correction
└─ Extended Stats -> correlation correction
│
▼
Stable access path and join plan tuning
이 흐름은 튜닝의 초점이 "인덱스 유무"에서 "통계 기반 추정 정확도"로 이동해 온 과정을 보여 준다.
👶 어린이를 위한 3줄 비유 설명
- 기수성은 상자 안에 서로 다른 색 블록이 몇 종류 있는지 세는 일이에요.
- 선택도는 선생님이 "빨간 블록만 가져와" 했을 때 전체 중 몇 개를 집게 되는지 보는 거예요.
- 분포도는 그 빨간 블록이 골고루 퍼져 있는지 한쪽에만 몰려 있는지 알려줘서, 어디부터 찾을지 정하게 해 줘요.