2025년 7월 29일
카테고리 : DB이론
조회 : 32|4분 읽기
뷰(View)와 인덱스(Index)
뷰(View)와 인덱스(Index), 정말 장점만 있는 만능 도구일까요?
데이터베이스 최적화라고 하면 보통은 조회 성능을 개선하는 것을 떠올리게 됩니다.
이때 흔히 사용하는 대표적인 방법은 인덱스를 추가하거나, 복잡한 쿼리를 뷰(View)로 캡슐화하는 것입니다.
이러한 방식은 분명 개발자의 작업 시간과 RDBMS의 실행 시간을 단축해줍니다.
하지만 정말 장점만 있을까요?
View와 Index는 언제 사용할까요?
다음과 같은 상황에서 View와 Index는 자주 사용됩니다.
복잡한 조인 쿼리를 반복적으로 사용할 때 → 뷰(View)로 캡슐화
WHERE, ORDER BY, JOIN이 느릴 때 → 인덱스를 추가하여 해결
이 두 기술은 성능 개선을 위한 강력한 도구입니다.
그러나 구조와 한계를 이해하지 못하고 사용하는 경우 오히려 성능 문제를 유발할 수 있습니다.
🧠 View / Index 구조 이해
✅ View 구조와 특징
뷰(View)는 SELECT 쿼리를 논리적으로 감싼 가상 테이블입니다.
비즈니스 로직이 복잡하거나 컬럼 수가 많을 때 데이터 추상화 및 재사용에 유리합니다.
장점
- 복잡한 쿼리를 캡슐화하여 재사용성을 높일 수 있습니다.
- 민감 정보를 숨길 수 있어 보안에 유리합니다.
- 실제 테이블 구조 변경에도 API 구조는 안정적으로 유지할 수 있습니다.
단점
- 일반 뷰는 항상 원본 테이블을 참조하기 때문에 성능 향상이 없습니다.
- 뷰 안에 뷰가 중첩되면 디버깅 및 유지보수가 어려워집니다.
- 조인 기반 뷰는 대부분 INSERT, UPDATE, DELETE가 제한됩니다.
💡 Materialized View(물리 뷰)를 사용하면 데이터를 캐시처럼 저장하여 성능을 향상시킬 수 있지만, 정기적 갱신이 필요하며 운영 비용이 발생합니다.
✅ Index 구조와 특징
인덱스(Index)는 WHERE, JOIN, ORDER BY 조건에서 검색 속도를 향상시키기 위한 데이터 구조입니다.
대부분의 RDBMS는 인덱스를 B-Tree 또는 B+Tree 구조로 구성합니다.
장점
- 조건절 탐색 시 평균 시간 복잡도 O(log n)으로 빠르게 탐색할 수 있습니다.
- ORDER BY, GROUP BY 등 정렬 연산을 최적화할 수 있습니다.
단점
- INSERT, UPDATE, DELETE 시 인덱스까지 함께 갱신되어 쓰기 성능이 저하될 수 있습니다.
- 인덱스 자체가 디스크 공간을 추가로 차지합니다.
- 잘못 설계된 인덱스는 오히려 성능을 악화시키며, 관리 비용만 증가시킬 수 있습니다.
❗ 왜 인덱스를 써도 느릴 수 있을까요?
SELECT 쿼리는 인덱스를 직접 사용하는 주체가 아니라,
옵티마이저가 인덱스를 사용할지 말지를 판단하는 대상일 뿐입니다.
느릴 수 있는 주요 이유
-
인덱스를 타지 않는 쿼리
- 예: WHERE UPPER(name) = 'JOHN' → 함수 때문에 인덱스 무시됨
-
선택도(Selectivity)가 낮은 컬럼예: gender = 'M'처럼 중복률 높은 컬럼은 풀 스캔이 더 빠름
-
정렬 조건과 인덱스가 불일치
-
옵티마이저 판단에 따라 인덱스가 무시될 수 있음
-
디스크 I/O 병목으로 인한 지연 발생
🎯 오라클 힌트절로 인덱스 제어하기
실행 계획이 옵티마이저 판단에 의해 예기치 않게 풀 스캔으로 떨어질 경우,
오라클에서는 힌트절을 사용해 인덱스 활용을 강제할 수 있습니다.
예:
sql1SELECT /*+ INDEX(t idx_user_id) */ * 2FROM USER_TABLE t 3WHERE user_id = '123';
- INDEX(t idx_user_id)는 테이블 t에서 인덱스 idx_user_id를 명시적으로 사용하라는 의미입니다.
- 그 외에도 FULL, USE_NL, LEADING, INDEX_COMBINE, INDEX_SKIP_SCAN 등 다양한 힌트가 존재합니다.
💡 힌트는 인덱스를 생성하는 것이 아닙니다. 반드시 인덱스가 실제로 존재해야 하며, EXPLAIN PLAN을 통해 실제로 사용되었는지 검증하는 것이 중요합니다.
📋 View와 Index 비교 요약표
| 항목 | View (뷰) | Index (인덱스) |
|---|---|---|
| 목적 | 쿼리 단순화 / 보안 추상화 | 검색 속도 향상 |
| 사용 시점 | 복잡한 쿼리 재사용 / 보안 필터 필요할 때 | WHERE, JOIN, ORDER BY 성능 향상 필요할 때 |
| 장점 | 재사용성, 유지보수성, 보안성 | 빠른 탐색, 정렬 최적화 |
| 단점 | 성능 향상 없음, 쓰기 제한, 중첩 시 복잡성 | 쓰기 성능 저하, 디스크 사용 증가, 튜닝 필요 |
🧑💻 실무 적용 사례
✅ 뷰 사용
우리 회사에서는 고객센터 요청에 따라 사용자의 상태를 빠르게 파악해야 하는 일이 자주 발생했습니다.
이때 고객 정보를 담고 있는 통신사별 테이블이 3개(SK, KT, LG)로 분리되어 있고,
부가서비스 가입 여부나 본인인증 수단(토스, 네이버 등)도 별도 테이블로 관리되고 있었습니다.
이런 조건을 매번 복잡한 UNION과 JOIN 쿼리로 작성하는 데 시간이 오래 걸리고, 반복 작업이 많았습니다.
그래서 이 모든 정보를 조합한 뷰(View)를 만들어 두었고, 이를 통해 다음과 같은 효과를 얻을 수 있었습니다:
- 쿼리 작성 시간 단축: 고객센터 요청 시 SELECT 한 줄로 필요한 정보 조회 가능
- 재사용성: 백오피스/로그 확인/운영툴에서 다수의 개발자가 동일 쿼리 활용
- 노출 범위 제어: 뷰 설계 시 SELECT 필드를 제한함으로써 민감 정보는 의도적으로 제외 가능
✅ 인덱스 사용 예시 (예시용 가상 테이블 기반)
📦 배송 상태 조회 성능 개선 사례
운영 중이던 고객센터 시스템에서 최근 30일 내 **‘배송 완료되지 않은 주문’**을 조회하는 쿼리는 다음과 같이 작성되어 있었습니다:
sql1SELECT * 2FROM DELIVERY_STATUS 3WHERE STATUS != 'DELIVERED' 4 AND ORDER_DATE >= SYSDATE - 30;
하지만 이 테이블에는 하루 수천 건이 누적되어 수백만 건으로 커졌고,
STATUS != 'DELIVERED'라는 부정 조건(Not Equal) 때문에 인덱스가 무시되고 Full Table Scan이 발생했습니다.
🎯 이제 어떤 방법으로 인덱스를 사용 가능하게 할 수 있을까요?
1. STATUS != 'DELIVERED' → STATUS IN ('PREPARING', 'SHIPPING', 'RETURNED')
2. (STATUS, ORDER_DATE) 순서의 복합 인덱스 생성
3. WHERE 조건 순서 조정 및 실행계획(Explain Plan) 검토로 인덱스 활용 유도
✅ 해당 방법들을 사용하여 얻을 수 있는 결과는
1. 기존 평균 6~8초 걸리던 응답 시간이 0.4초 이내로 단축
2. 유사 조건을 사용하는 다른 쿼리에서도 동일 인덱스 재활용
3. 병목 제거로 서버 부하 감소 및 사용자 응답 속도 향상
💡 본 사례는 설명을 위한 예시 테이블(DELIVERY_STATUS)을 기반으로 구성되었으며, 실무에서 유사한 조건을 가진 환경을 가정한 예입니다.
🔚 마무리하며
뷰와 인덱스는 단순히 “쓰기 편한 도구”가 아니라,
데이터베이스의 구조와 사용 패턴을 기반으로 신중하게 설계해야 하는 성능 개선 전략입니다.
단순한 사용만으로는 성능 향상이 보장되지 않으며,
실행 계획(EXPLAIN PLAN), 옵티마이저 전략, 데이터 통계 등과 함께 고려해야 진짜 효과를 얻을 수 있습니다.