Cardinality (카디널리티)
- "이 컬럼은 카디널리티가 낮아서 인덱스 효과가 없다"
- "캐시 키의 카디널리티가 너무 높다"
카디널리티는 데이터를 다루는 거의 모든 영역에서 등장하는 기초 개념입니다. 한 단어로 데이터의 분포를 표현할 수 있는 힘이 여기에 있습니다.
카디널리티란
카디널리티(Cardinality)는 집합에서 고유한 원소의 수입니다. 수학의 집합론에서 출발한 개념이고, 데이터 영역에서는 어떤 데이터 집합에 서로 다른 값이 몇 개인가를 뜻합니다.
이 글 전체에서 아래 테이블을 예시로 사용합니다.
| id | user_id | status | gender | created_at |
|---|---|---|---|---|
| 1 | 1042 | PAID | M | 2026-01-15 |
| 2 | 2981 | PENDING | F | 2026-02-03 |
| 3 | 1042 | PAID | M | 2026-03-22 |
| 4 | 5520 | CANCELLED | F | 2026-04-01 |
| 5 | 3301 | PAID | M | 2026-04-10 |
| ... | ... | ... | ... | ... |
| 총 2억 건 |
각 컬럼의 카디널리티를 비교하면:
컬럼별 카디널리티 비교
막대가 길수록 한 그룹에 많은 행이 몰립니다 (N ÷ K)
id고유값 2억user_id고유값 500만created_at고유값 ~수십만status고유값 3gender고유값 2같은 테이블, 같은 2억 건이라도 컬럼마다 카디널리티가 다릅니다. 핵심은 절대적인 숫자가 아니라 전체 행 수 대비 고유값의 비율입니다.
왜 중요한가
카디널리티가 중요한 이유는 단순합니다. 데이터를 분류·검색·분산할 때, 고유값이 몇 개인지에 따라 전략이 완전히 달라지기 때문입니다.
나누기의 원리
데이터를 다루는 시스템은 끊임없이 데이터를 "나눕니다" — 인덱스는 값 기준으로 나누고, 캐시는 키 기준으로 나누고, 파티셔닝은 범위/해시 기준으로 나눕니다. 이때 나누는 기준의 카디널리티가 낮으면 한쪽에 데이터가 몰리고, 높으면 골고루 분산됩니다.
gender 컬럼(카디널리티 2)으로 2억 건을 나누면 한 그룹에 1억 건이 몰립니다. user_id 컬럼(카디널리티 500만)으로 나누면 그룹당 평균 40건입니다. 같은 "나누기"인데 결과가 완전히 다릅니다.
흔한 오해
판단 기준
높은 카디널리티
고유값이 전체 행 수에 가까운 경우입니다.
| 컬럼 | 설명 |
|---|---|
id (PK) | 행마다 다름. 카디널리티 = 행 수 |
email | 사용자마다 고유 |
UUID | 설계상 중복 불가 |
created_at (타임스탬프) | 밀리초 단위면 거의 고유 |
특징: 특정 값을 지정하면 소수의 행만 매칭됩니다. "정확히 이 값"을 찾는 검색에 유리합니다.
낮은 카디널리티
고유값이 전체 행 수 대비 극히 적은 경우입니다.
| 컬럼 | 설명 |
|---|---|
gender | 2~3가지 |
status | PAID, PENDING, CANCELLED 등 한정 |
is_active | true / false |
country | 최대 ~200개, 대부분 상위 5개국에 집중 |
특징: 특정 값을 지정해도 대량의 행이 매칭됩니다. "이 값"을 찾아도 전체의 30~50%가 걸릴 수 있습니다.
어디서 마주치는가
카디널리티는 특정 기술에 국한된 개념이 아닙니다. 데이터를 "나누는" 모든 영역에서 등장합니다.
1. 인덱스 설계
인덱스는 컬럼 값을 기준으로 행을 빠르게 찾는 구조입니다. 카디널리티가 높은 컬럼에 인덱스를 걸면 소수의 행만 읽어 효율적입니다. user_id(500만 고유값)에 인덱스를 걸고 WHERE user_id = 1042를 실행하면 평균 40건만 읽습니다.
반면 gender(2 고유값)에 인덱스를 걸고 WHERE gender = 'M'을 실행하면 1억 건이 매칭됩니다. 이 경우 인덱스를 타는 것(Random I/O로 1억 건)보다 풀 테이블 스캔풀 테이블 스캔(Sequential I/O로 2억 건)이 더 빠릅니다. 카디널리티가 낮은 컬럼의 단독 인덱스는 효과가 없습니다.
2. 캐시 키 설계
캐시는 키를 기준으로 결과를 저장합니다. 카디널리티는 캐시의 적중률과 메모리 사용량을 결정합니다.
- 카디널리티가 적당히 높은 키 —
user_id기준 캐시. 500만 개의 키가 생기지만 같은 사용자의 반복 요청에 적중합니다. - 카디널리티가 너무 높은 키 — 요청 URL 전체를 키로 쓰면 거의 모든 요청이 고유해져 캐시 적중률이 0에 가까워집니다. 메모리만 낭비합니다.
- 카디널리티가 너무 낮은 키 —
status기준 캐시. 3개의 키에 수천만 건의 결과가 매달려, 키 하나가 만료되면 대량의 DB 요청이 한꺼번에 발생할 수 있습니다.
3. 파티셔닝 / 샤딩
데이터를 여러 노드에 분산할 때, 파티션 키의 카디널리티가 **데이터 쏠림(skew)**을 결정합니다.
user_id(카디널리티 500만)로 해시 파티셔닝하면 노드 간 균등 분산됩니다.country(카디널리티 ~200)로 파티셔닝하면 한국·미국 등 상위 국가에 데이터가 몰립니다. 특정 노드만 과부하에 걸리는 핫스팟 문제가 발생합니다.
4. 모니터링 라벨
Prometheus, Datadog 같은 시계열 DB에서 메트릭 라벨의 카디널리티가 높으면 **시계열 폭발(cardinality explosion)**이 발생합니다.
http_requests_total{method="GET", path="/api/users"} — method는 카디널리티 5, 수백 정도라 감당 가능합니다. 여기에 path는 카디널리티 수십user_id(카디널리티 500만)를 라벨로 추가하면 시계열 수가 수백만 배로 폭증해 DB가 감당할 수 없게 됩니다.
트레이드오프
카디널리티 트레이드오프
높다고 항상 좋은 것도, 낮다고 항상 나쁜 것도 아닙니다
| 영역 | 높은 카디널리티 | 낮은 카디널리티 |
|---|---|---|
| 인덱스 | 소수 행만 매칭 → 효율적 | 대량 행 매칭 → 인덱스 의미 없음 |
| 캐시 키 | 키가 많아 메모리 부담 ↑ | 적중률 높지만 한 키에 부하 집중 |
| 파티셔닝 | 균등 분산 | 핫스팟 위험 |
| 모니터링 라벨 | 시계열 폭발 위험 | 안전하지만 세분화 불가 |
카디널리티 자체에 "좋다/나쁘다"는 없습니다. 맥락에 따라 적절한 수준이 다릅니다.
- 인덱스, 파티셔닝: 높을수록 유리한 경향
- 캐시 키: 적당히 높은 것이 이상적 (적중률과 메모리 사용량의 균형)
- 모니터링 라벨: 낮을수록 안전 (시계열 수 억제)
마무리
카디널리티는 고유값이 몇 개인가라는 단순한 정의이지만, 인덱스 설계부터 캐시 전략, 파티셔닝, 모니터링까지 데이터를 나누는 모든 곳에서 의사결정의 출발점이 됩니다. 어떤 기술을 쓰든 "이 기준으로 나누면 한 그룹에 몇 건이 들어가는가?"를 먼저 떠올릴 수 있다면 카디널리티를 제대로 이해한 것입니다.