(→기본 설명) |
태그: 편집 취소 |
||
| 369번째 줄: | 369번째 줄: | ||
: {{{답변2|답변}}} | : {{{답변2|답변}}} | ||
[[분류:{{{분류| | [[분류:{{{분류|기타}}}]] | ||
2025년 10월 2일 (목) 18:54 기준 최신판
문서 제목 없음
값의 의미
- 범위
- **최소값**: 테이블의 블록 수 (완벽하게 정렬된 경우) - **최대값**: 테이블의 행 수 (완전히 무작위로 분산된 경우)
해석 방법
-- Clustering Factor 확인
SELECT
index_name,
table_name,
clustering_factor,
num_rows,
leaf_blocks,
-- 테이블 블록 수
(SELECT blocks FROM dba_tables t
WHERE t.owner = i.table_owner
AND t.table_name = i.table_name) AS table_blocks
FROM dba_indexes i
WHERE table_owner = 'HR'
AND table_name = 'EMPLOYEES';
- 판단 기준:**
| Clustering Factor | 상태 | 의미 | |------------------|------|------| | ≈ 테이블 블록 수 | **좋음** ✅ | 데이터가 인덱스 순서대로 잘 정렬됨 | | 테이블 블록 수 ~ 행 수 사이 | 보통 | 부분적으로 정렬됨 | | ≈ 테이블 행 수 | **나쁨** ❌ | 데이터가 무작위로 흩어져 있음 |
---
Clustering Factor의 계산 원리
- 인덱스를 순차적으로 스캔하면서:
- - 이전 행과 다른 블록에 있으면: CF++
- - 이전 행과 같은 블록에 있으면: CF 증가 없음
예제로 이해하기
- 시나리오 1: 좋은 Clustering Factor
인덱스 순서: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
블록 배치: [1,2,3] [4,5,6] [7,8,9] [10]
Block1 Block2 Block3 Block4
Clustering Factor = 4 (블록 수)
시나리오 2: 나쁜 Clustering Factor
인덱스 순서: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
블록 배치: [1] [5] [2] [7] [3] [9] [4] [10] [6] [8]
B1 B2 B3 B4 B5 B6 B7 B8 B9 B10
Clustering Factor = 10 (행 수)
- 성능에 미치는 영향
- 좋은 Clustering Factor (낮은 값)
```sql -- 예: CF = 1,000 (블록 수와 유사) SELECT * FROM employees WHERE department_id BETWEEN 10 AND 50;
-- 결과: 약 1,000개 블록만 읽음 -- 각 블록에서 여러 행을 읽을 수 있음 ```
- 장점:**
- 인덱스 Range Scan이 효율적 - 물리적 I/O 최소화 - Buffer Cache 효율 증가
- 나쁜 Clustering Factor (높은 값)
```sql -- 예: CF = 100,000 (행 수와 유사) SELECT * FROM employees WHERE department_id BETWEEN 10 AND 50;
-- 결과: 약 50,000개 블록 읽음 -- 각 행마다 다른 블록을 읽어야 함 ```
- 단점:**
- 많은 물리적 I/O 발생 - 동일 블록을 반복 읽기 - Full Table Scan이 더 효율적일 수 있음
---
- 실무 조회 쿼리
- 1. Clustering Factor 상태 확인
```sql SELECT
i.owner,
i.table_name,
i.index_name,
i.clustering_factor,
t.num_rows,
t.blocks AS table_blocks,
-- CF 품질 지표
ROUND(i.clustering_factor / NULLIF(t.blocks, 0), 2) AS cf_ratio,
CASE
WHEN i.clustering_factor <= t.blocks * 1.2 THEN '좋음 ✅'
WHEN i.clustering_factor <= t.blocks * 5 THEN '보통 ⚠️'
WHEN i.clustering_factor <= t.num_rows * 0.5 THEN '나쁨 ❌'
ELSE '매우 나쁨 🚫'
END AS cf_status,
-- 효율성 점수 (낮을수록 좋음)
ROUND((i.clustering_factor / NULLIF(t.num_rows, 0)) * 100, 2) AS efficiency_pct
FROM dba_indexes i JOIN dba_tables t ON i.table_owner = t.owner
AND i.table_name = t.table_name
WHERE i.owner = 'HR'
AND t.num_rows > 0
ORDER BY efficiency_pct DESC; ```
- 2. 문제가 있는 인덱스 찾기
```sql SELECT
i.owner, i.table_name, i.index_name, i.clustering_factor, t.blocks AS table_blocks, t.num_rows, ROUND(i.clustering_factor / t.num_rows * 100, 2) AS cf_pct, ROUND((t.num_rows * t.avg_row_len) / 1024 / 1024, 2) AS table_size_mb
FROM dba_indexes i JOIN dba_tables t ON i.table_owner = t.owner
AND i.table_name = t.table_name
WHERE i.owner NOT IN ('SYS', 'SYSTEM')
AND t.num_rows > 10000 -- 작은 테이블 제외 AND i.clustering_factor > t.blocks * 10 -- CF가 블록 수의 10배 이상
ORDER BY (i.clustering_factor / t.num_rows) DESC; ```
- 3. 인덱스 효율성 분석
```sql WITH index_stats AS (
SELECT
i.owner,
i.table_name,
i.index_name,
i.clustering_factor,
t.blocks,
t.num_rows,
-- 인덱스로 100행을 읽을 때 예상 블록 접근 수
CASE
WHEN t.num_rows > 0 THEN
ROUND((i.clustering_factor / t.num_rows) * 100, 0)
ELSE 0
END AS blocks_per_100_rows
FROM dba_indexes i
JOIN dba_tables t ON i.table_owner = t.owner
AND i.table_name = t.table_name
WHERE i.owner = 'HR'
) SELECT
owner,
table_name,
index_name,
clustering_factor,
blocks AS table_blocks,
num_rows,
blocks_per_100_rows,
CASE
WHEN blocks_per_100_rows <= 10 THEN 'Range Scan 효율적'
WHEN blocks_per_100_rows <= 50 THEN 'Range Scan 사용 가능'
ELSE 'Full Scan 고려'
END AS recommendation
FROM index_stats ORDER BY blocks_per_100_rows DESC; ```
---
- Clustering Factor 개선 방법
- 방법 1: 테이블 재구성 (MOVE)
```sql -- 인덱스 컬럼 순서대로 테이블 재정렬 ALTER TABLE hr.employees MOVE;
-- 인덱스 재구성 ALTER INDEX hr.emp_dept_idx REBUILD;
-- 통계 재수집 EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'EMPLOYEES');
-- CF 확인 SELECT index_name, clustering_factor FROM user_indexes WHERE index_name = 'EMP_DEPT_IDX'; ```
- 방법 2: 테이블을 인덱스 순서로 재생성
```sql -- 임시 테이블 생성 (인덱스 순서대로) CREATE TABLE employees_new AS SELECT * FROM employees ORDER BY department_id, employee_id;
-- 원본 테이블 교체 DROP TABLE employees; RENAME employees_new TO employees;
-- 인덱스 재생성 CREATE INDEX emp_dept_idx ON employees(department_id);
-- 통계 수집 EXEC DBMS_STATS.GATHER_TABLE_STATS('HR', 'EMPLOYEES'); ```
- 방법 3: Partitioning 사용
```sql -- 파티션 테이블로 변환 ALTER TABLE employees MODIFY PARTITION BY RANGE (department_id) (
PARTITION p1 VALUES LESS THAN (20), PARTITION p2 VALUES LESS THAN (40), PARTITION p3 VALUES LESS THAN (60), PARTITION p4 VALUES LESS THAN (MAXVALUE)
);
-- 로컬 인덱스 생성 CREATE INDEX emp_dept_idx ON employees(department_id) LOCAL; ```
- 방법 4: IOT (Index-Organized Table) 사용
```sql -- 기존 테이블을 IOT로 변환 CREATE TABLE employees_iot ORGANIZATION INDEX INCLUDING employee_id OVERFLOW AS SELECT * FROM employees; ```
---
- Optimizer가 Clustering Factor를 사용하는 방법
```sql -- 실행 계획에서 Clustering Factor의 영향 확인 EXPLAIN PLAN FOR SELECT * FROM employees WHERE department_id BETWEEN 10 AND 50;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(null, null, 'BASIC +COST'));
-- Cost 계산에 Clustering Factor가 사용됨 -- Cost = (Clustering Factor / Table Blocks) * Index Selectivity ```
- Optimizer의 판단:**
- **CF가 낮으면**: Index Range Scan 선호 - **CF가 높으면**: Full Table Scan 고려
---
- 실전 모니터링 스크립트
```sql -- 일일 CF 모니터링 CREATE OR REPLACE VIEW v_clustering_factor_monitor AS SELECT
i.owner,
i.table_name,
i.index_name,
i.clustering_factor,
t.blocks,
t.num_rows,
ROUND(i.clustering_factor / NULLIF(t.blocks, 0), 2) AS cf_block_ratio,
ROUND(i.clustering_factor / NULLIF(t.num_rows, 0) * 100, 2) AS cf_row_pct,
i.last_analyzed,
CASE
WHEN i.clustering_factor <= t.blocks * 2 THEN 'GOOD'
WHEN i.clustering_factor <= t.blocks * 10 THEN 'FAIR'
ELSE 'POOR'
END AS status
FROM dba_indexes i JOIN dba_tables t ON i.table_owner = t.owner
AND i.table_name = t.table_name
WHERE i.owner NOT IN ('SYS', 'SYSTEM', 'XDB', 'OUTLN')
AND t.num_rows > 1000;
-- 사용 SELECT * FROM v_clustering_factor_monitor WHERE status = 'POOR' ORDER BY cf_row_pct DESC; ```
---
- 주의사항
1. **통계 정보 최신화**
```sql
-- CF는 통계 수집 시 계산됨
EXEC DBMS_STATS.GATHER_INDEX_STATS('HR', 'EMP_DEPT_IDX');
```
2. **DML 작업 후 CF 변화**
- INSERT/UPDATE/DELETE 후 CF가 나빠질 수 있음 - 주기적인 통계 수집 필요
3. **파티션 테이블**
- 파티션별로 CF가 다를 수 있음 - USER_IND_PARTITIONS에서 확인
4. **Multiblock Read**
- CF가 나빠도 db_file_multiblock_read_count가 크면 영향 감소
---
- 요약
| 상황 | Clustering Factor | 권장 사항 | |-----|------------------|---------| | OLTP, 자주 Range Scan | 테이블 블록 수와 유사 | 테이블 재구성 고려 | | Batch, Full Scan 위주 | 높아도 무관 | 현상 유지 | | 자주 변경되는 테이블 | 주기적으로 나빠짐 | 파티셔닝 검토 | | 대용량 테이블 | 매우 높음 | IOT 또는 파티셔닝 |
Clustering Factor는 인덱스 성능을 판단하는 핵심 지표이므로, DBA는 정기적으로 모니터링하고 필요시 개선 작업을 수행해야 합니다!
예제
{{{예제}}}
이전글/다음글
- [[]]
- [[]]
관련 문서
- [[]]
- [[]]
FAQ
- 질문
- 답변
- 질문
- 답변