편집 요약 없음 태그: 되돌려진 기여 |
편집 요약 없음 태그: 수동 되돌리기 |
||
| 240번째 줄: | 240번째 줄: | ||
{{결론 | {{결론 | ||
|내용= [결론] | |내용= [결론] Cardinality vs. Selectivity | ||
Cardinality vs. Selectivity | |||
* 실무 팁: Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 미친다. | * 실무 팁: Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 미친다. | ||
}} | }} | ||
2026년 9월 16일 (수) 17:31 기준 최신판
Cardinality (카디널리티) 와 Selectivity (선택도)
vpn_key 핵심: High Cardinality = Low Selectivity = 인덱스 효과적 = 성능 좋음
- Cardinality (카디널리티,고유값 수)
- 특정 연산이나 조건에서 반환되는 예상 행의 개수
- 절대적인 수치 (행 개수)
- 실행 계획의 “Rows” 컬럼에 표시됨
- 예시:
성별 컬럼: Cardinality = 2 (남, 여)
주민번호 컬럼: Cardinality = 1,000,000 (100만 명이면 100만)
- Selectivity (선택도)
- 전체 행 중에서 조건을 만족하는 행의 비율 (선택된 row 수 / 전체 row 수)
- 상대적인 비율 (0 ~ 1 사이의 값, 또는 0% ~ 100%)
- 조건의 “선택적” 정도를 나타냄
- 예시:
성별='남': Selectivity = 0.5 (50%)
특정 주민번호: Selectivity = 0.000001 (0.0001%)
playlist_add_check실무에서 사용하는 방식
"이 컬럼 카디널리티가 높아서 인덱스 효과 좋을 거야" = "이 컬럼 고유값이 많아서 인덱스 효과 좋을 거야"
"성별 컬럼은 카디널리티가 2야" = "성별 컬럼은 고유값이 2개야"
"카디널리티 체크해봐"= "고유값 개수 확인해봐"Cardinality = Total Rows × Selectivity Selectivity = Cardinality / Total Rows
실무 예제
- 예제 1: 단순 테이블
-- 직원 테이블 CREATE TABLE employees ( emp_id NUMBER, dept_id NUMBER, salary NUMBER, status VARCHAR2(20) ); -- 통계 정보 -- Total Rows: 10,000명 -- dept_id = 10: 500명 -- salary > 5000: 3,000명 -- status = 'ACTIVE': 9,000명
- -- Query 1
SELECT * FROM employees WHERE dept_id = 10;
- Selectivity = 500 / 10,000 = 0.05 (5%)
- Cardinality = 500 (행)
- -- Query 2
SELECT * FROM employees WHERE salary > 5000;
- Selectivity = 3,000 / 10,000 = 0.3 (30%)
- Cardinality = 3,000 (행)
- -- Query 3
SELECT * FROM employees WHERE status = 'ACTIVE';
- Selectivity = 9,000 / 10,000 = 0.9 (90%)
- Cardinality = 9,000 (행)
실행 계획 확인
-- 통계 수집 EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT', 'EMPLOYEES'); -- 실행 계획 확인 EXPLAIN PLAN FOR SELECT * FROM employees WHERE dept_id = 10; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
- 실행 계획 결과:
------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 500 | 5000 | 10 (0)| |* 1 | TABLE ACCESS FULL| EMPLOYEES | 500 | 5000 | 10 (0)| ------------------------------------------------------------------------- Predicate Information: 1 - filter("DEPT_ID"=10) Rows = 500 ← 이것이 Cardinality
Selectivity 계산 공식
- 1. 등호(=) 조건
-- WHERE column = value Selectivity = 1 / NUM_DISTINCT 예: dept_id의 distinct 값이 20개 Selectivity = 1 / 20 = 0.05
- 2. 범위 조건
-- WHERE column > value Selectivity = (MAX_VALUE - value) / (MAX_VALUE - MIN_VALUE) 예: salary BETWEEN 3000 AND 10000 조건: salary > 5000 Selectivity = (10000 - 5000) / (10000 - 3000) = 5000/7000 ≈ 0.71
- 3. NULL 조건
-- WHERE column IS NULL Selectivity = NUM_NULLS / NUM_ROWS 예: 10,000행 중 500개가 NULL Selectivity = 500 / 10,000 = 0.05
- 4. 복합 조건 (AND)
-- WHERE col1 = 10 AND col2 = 'A' Selectivity = Selectivity(col1) × Selectivity(col2) 예: Selectivity(col1) = 0.05 Selectivity(col2) = 0.1 Total Selectivity = 0.05 × 0.1 = 0.005 (0.5%) Cardinality = 10,000 × 0.005 = 50
- 5. 복합 조건 (OR)
-- WHERE col1 = 10 OR col2 = 'A' Selectivity = Sel(col1) + Sel(col2) - (Sel(col1) × Sel(col2)) 예: Selectivity(col1) = 0.05 Selectivity(col2) = 0.1 Total Selectivity = 0.05 + 0.1 - (0.05 × 0.1) = 0.145 Cardinality = 10,000 × 0.145 = 1,450
통계 정보에서 확인
-- Selectivity 관련 통계 SELECT table_name, column_name, num_distinct, -- distinct 값 개수 num_nulls, -- NULL 개수 density, -- 1/num_distinct (Selectivity) num_rows -- 전체 행 수 FROM user_tab_col_statistics WHERE table_name = 'EMPLOYEES';
- 결과 예시:
COLUMN_NAME NUM_DISTINCT NUM_NULLS DENSITY NUM_ROWS --------------------------------------------------------- EMP_ID 10000 0 0.0001 10000 DEPT_ID 20 0 0.05 10000 ← Selectivity SALARY 500 100 0.002 10000 STATUS 2 0 0.5 10000
실무에서의 중요성
- 인덱스 생성 판단
-- Selectivity가 낮을수록 (선택적일수록) 인덱스 효과 좋음 -- 좋은 경우 (Selectivity: 0.001%) CREATE INDEX idx_emp_id ON employees(emp_id); -- emp_id는 고유값, 조회 시 1-2건만 반환 -- 나쁜 경우 (Selectivity: 90%) CREATE INDEX idx_status ON employees(status); -- status는 ACTIVE/INACTIVE 2개 값, 조회 시 9000건 반환 -- Full Table Scan이 더 효율적
- 조인 순서 결정
-- Cardinality가 작은 테이블을 먼저 처리 SELECT /*+ LEADING(d e) */ * FROM departments d JOIN employees e ON d.dept_id = e.dept_id WHERE d.location = 'SEOUL'; -- d 테이블의 Cardinality: 10 (Selectivity 1%) -- e 테이블의 Cardinality: 10000 (Selectivity 100%) -- → departments를 먼저 필터링하는 것이 효율적
- 통계 정확도 확인
-- 실제 Cardinality vs 예상 Cardinality SELECT /*+ GATHER_PLAN_STATISTICS */ * FROM employees WHERE dept_id = 10; SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(format=>'ALLSTATS LAST'));
- 결과:
------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows | A-Rows | ... ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 520 | ... |* 1 | TABLE ACCESS FULL | EMP | 1 | 500 | 520 | ... ------------------------------------------------------------------- E-Rows: 500 ← 예상 Cardinality (Estimated) A-Rows: 520 ← 실제 Cardinality (Actual) 차이: 4% (통계가 정확함)
- 인덱스 생성 판단
menu_book [결론] Cardinality vs. Selectivity
- 실무 팁: Selectivity가 5% 이하일 때 인덱스 사용이 효과적이고, Cardinality는 조인 순서와 메모리 할당에 영향을 미친다.
| 구분 | Cardinality | Selectivity |
|---|---|---|
| 의미 | 반환되는 행의 개수 | 선택되는 행의 비율 |
| 단위 | 행 (rows) | 비율 (0~1) |
| 타입 | 절대값 | 상대값 |
| 사용처 | 실행 계획, Cost 계산 | 조건 효율성 판단 |
| 예시 | 500 rows | 5% (0.05) |