01 index
01 index
1. Note
- JPA를 사용하면서 인덱스가 과거와는 조금 패러다임을 가지게됨
- 기존에는 쿼리 위주로 데이터를 조회하고 한번에 작업하는 형태
- JPA는 빠르게 조회해서 ORM기준으로 무엇인가 처리하기 때문에
- Query 자체는 굉장히 단순해짐.
- Index는
- 너무 무리하지말고 흐름만 파악하고
- 기본에 충실하는 형태로 활용할 것
2. index
1. 인덱스
- 데이터베이스에서 특정 컬럼의 값을 기준으로 데이터를 빠르게 조회하기 위해 별도로 유지되는 자료구조
- 테이블의 일부 컬럼 값을 정렬된 구조(B-Tree 등)로 저장하고,
- 해당 값에 대응하는 데이터의 위치를 함께 관리하여 검색 성능을 향상시키는 객체
- Point
- 실제 데이터와 별도로 저장됨
- 조회 성능을 위해 존재
- 대신 쓰기 성능과 저장공간을 희생
- 내부적으로 정렬된 구조 유지
2. 인덱스의 필요성
- 장점
- 조회 성능 향상 (검색, 조건 조회, 정렬)
- 디스크 I/O 감소로 전체 성능 개선
- 대용량 데이터 처리에 유리
- 단점
- INSERT / UPDATE / DELETE 성능 저하
- 추가 저장공간 필요
- 잘못 설계 시 성능 오히려 악화
3. 인덱스 종류와 기준
- Note
- 대부분의 일반 인덱스는 B-Tree(B+Tree)로 구현되지만, 인덱스 종류 자체가 B-Tree를 의미하는 것
- 모든 인덱스가 B-Tree로 구현된건 아님 X
인덱스 종류 (논리적 분류)
종류 설명 특징 사용 상황 단일 인덱스 (Single Index) 하나의 컬럼에 대한 인덱스 가장 기본 WHERE email = ? 복합 인덱스 (Composite Index) 여러 컬럼을 묶은 인덱스 컬럼 순서 중요 WHERE name + age 유니크 인덱스 (Unique Index) 중복 값 허용 안함 데이터 무결성 보장 이메일, 아이디 클러스터드 인덱스 (Clustered Index) 실제 데이터가 인덱스 순으로 정렬 테이블당 1개 PK (기본키) 논클러스터드 인덱스 (Non-Clustered) 별도의 인덱스 구조 데이터와 분리 일반 검색 커버링 인덱스 (Covering Index) 쿼리에 필요한 컬럼을 모두 포함 테이블 접근 없음 성능 최적화 풀텍스트 인덱스 (Full-Text) 문자열 검색 최적화 LIKE보다 빠름 검색 기능 해시 인덱스 (Hash Index) 해시 기반 = 검색만 빠름 정확 일치 - 인덱스 구조 (물리적 구현)
| 구조 | 설명 |
|---|---|
| B-Tree / B+Tree | DB 기본 인덱스 구조 |
| Hash | = 검색 특화 |
| (기타) | Bitmap 등 |
3. B-Tree
1. 비트리(B-Tree)
- 디스크 기반 DB에서 읽기/쓰기 균형이 가장 좋은 구조라서 많이 사용
- 한번 연산할때마다 넓은 범위의 key들을 제거가 가능함.
2. B-Tree
- 노드(Node) 구조
1 2 3 4 5 6
# 하나의 노드에 여러 개의 key(값) 저장 # key 사이마다 자식 노드 포인터 존재 [ key1 | key2 | key3 ] ↓ ↓ ↓ child child child - 정렬 규칙
1 2 3 4 5 6 7 8 9
# 이거 아래의 자식들도 값으로 의미가 있고 # 이거 자체도 의미가 있음 # 10을 찾는 경우 아래 노드까지 안가고 여기서 멈출수도 있음 # 계속 최소 Key값, 최대 key값 수를 맞춰가면서 계속 정렬함. [ 10 | 20 | 30 ] 10보다 작은 값 → 왼쪽 자식 10~20 사이 → 두 번째 자식 20~30 사이 → 세 번째 자식 30보다 큰 값 → 마지막 자식
- 트리 구조 특징
- 모든 리프 노드가 같은 깊이 (균형 유지)
- 트리 높이가 낮음
- 검색 시 위 → 아래로 내려감
3. 주로 사용하는 이유
- 디스크 I/O 최소화
- 한 노드에 많은 키를 저장 (fan-out 큼)
- 트리 높이가 낮음
- 적은 디스크 접근으로 데이터 조회 가능
- 정렬된 구조 유지
- 항상 값이 정렬된 상태
- 범위 조회 (>, <, BETWEEN) + ORDER BY에 매우 유리
- 읽기/쓰기 균형 잡힌 성능
- 조회: O(log N)
- 삽입/삭제: 균형 유지하며 안정적 수행
- 특정 상황에서 성능이 급격히 나빠지지 않음
- DB 저장 구조(페이지)와 궁합이 좋음
- 노드 = 디스크 페이지 단위
- 한 번 읽을 때 많은 데이터 확보
- DB 내부 구조에 최적화된 형태
4. B-Tree 장단점
- 장점
- 빠른 검색 성능 (O(log N))
- 정렬된 구조로 범위 조회에 강함 (>, <, BETWEEN)
- 트리 균형 유지로 안정적인 성능 보장
- 디스크 I/O 최소화에 유리 (높이가 낮음)
- 단점
- 구조가 복잡하여 구현 및 관리 비용 존재
- 삽입/삭제 시 노드 분할/병합 발생 → 쓰기 비용 증가
- 메모리 기반 구조(해시 등)보다 단일 조회는 느릴 수 있음
- 완전 랜덤 접근보다 순차/범위 중심에 최적화됨
4. 인덱스를 거는 방법
1. Primary Key
- 테이블의 각 행을 고유하게 식별하기 위해 사용되는 특별한 인덱스
- 특징
- 테이블당 하나의 PRIMARY KEY만 정의할 수 있음
- PRIMARY KEY는 중복을 허용하지 않음
- PRIMARY KEY는 NULL 값을 허용하지 않음
- PRIMARY KEY 생성 시 대부분 인덱스가 자동으로 생성됨
- 일부 DB에서는 PRIMARY KEY가 클러스터형 인덱스로 사용됨
- 예시
1 2 3 4
CREATE TABLE user ( id INT PRIMARY KEY, -- user_id가 기본 키로 지정됨 email VARCHAR(255) NOT NULL -- email은 NULL을 허용하지 않음 );
2. Unique Index
- 특정 컬럼(또는 컬럼들의 조합)에 대해 중복된 값을 허용하지 않는 인덱스
- 특징
- 한 테이블에 여러 개의 UNIQUE INDEX를 생성할 수 있음
- UNIQUE INDEX는 NULL 값을 허용
- NULL 허용 방식은 DBMS마다 다름
- UNIQUE INDEX는 중복 값을 허용하지 않음
- 예시
1 2 3 4 5 6 7 8 9 10 11
CREATE TABLE user ( user_id INT PRIMARY KEY, email VARCHAR(255) NOT NULL, username VARCHAR(50) ); -- email 컬럼에 UNIQUE 인덱스 생성 (중복 이메일 허용 안 함) CREATE UNIQUE INDEX idx_user_email ON users(email); -- username 컬럼에도 UNIQUE 인덱스 생성 (NULL 허용, 중복 사용자명 허용 안 함) CREATE UNIQUE INDEX idx_user_username ON users(username);
3. 복합 인덱스 (Composite Index)
- 두 개 이상의 컬럼을 조합하여 생성된 인덱스
- 특징
- 여러 컬럼이 AND 조건으로 함께 사용될 때 성능을 향상
- 복합 인덱스는 정의된 컬럼 순서에 따라 동작
- 인덱스는 선행 컬럼부터 순서대로 사용
- 선행 컬럼을 포함하는 조건에서만 인덱스를 활용할 수 있음
- 예시
1 2 3 4 5
-- user 테이블에 user_id와 created_at 컬럼으로 복합 인덱스 생성 CREATE INDEX idx_user_user_id_created_at ON user (user_id, status); -- 특정 사용자의 특정 날짜 이후 주문 조회 SELECT * FROM user WHERE user_id = 1 AND created_at > '2025-01-16';
5. 인덱스 설계 시 주의사항
1. 과도한 인덱스 생성 지양
- 너무 많은 인덱스는 데이터 삽입(INSERT), 삭제(DELETE), 갱신(UPDATE) 작업의 성능을 심각하게 저하시킴
- 데이터가 변경될 때마다 관련 인덱스도 함께 갱신해야 하므로 추가적인 오버헤드가 발생함
- 권장 사항
- 실제로 자주 사용되는 쿼리에만 인덱스를 생성해야함.
- 주기적으로 데이터베이스 성능을 모니터링필요
- 오랜 기간 동안 사용되지 않거나 비효율적인 인덱스를 점검하여 제거하는
인덱스 최적화 작업을 수행해야함
2. 인덱스 크기 관리
- 대규모 데이터셋에서는 인덱스 자체의 크기가 커져 디스크를 많이 차지하고 메모리 사용량도 증가시킴
- 해결 방법
- 부분 인덱스(Partial Index/Filtered Index)
- 특정 조건의 데이터에만 인덱스를 생성하여 인덱스 크기를 줄임
- 일부 DBMS에서만 지원(PostgreSQL / SQL Server / SQLite 등)
- 커버링 인덱스(Covering Index)
- 필요한 컬럼을 모두 포함하여 인덱스로 만들어서 조회함
- 테이블 접근을 줄여 성능을 향상시키지만 커버링 인덱스 크기가 커질수도 있음.
- 부분 인덱스(Partial Index/Filtered Index)
3. 카디널리티(Cardinality) 고려
- 카디널리티는 컬럼이 가지는 고유 값의 개수” 또는 “데이터의 분포 다양성”
- 카디널리티가 높을수록 인덱스 성능이 좋아짐
- 예시
- 기준 테이블
user(id, email, gender, status, created_at) - gender (낮은 카디널리티)
- 전체 100만 건이어도 값은 2개뿐
- 인덱스 걸어도 대부분 “반 정도” 읽어야 함
- 거의 필터링 효과 없음
- email (높은 카디널리티)
aaa@test.com,bbb@test.com,ccc@test.com- 거의 전부 유니크로 인덱스 걸면 바로 1건으로 좁혀짐
- 기준 테이블
4. 쿼리 조건에 적합한 인덱스 설계
- 기본 원칙은 쿼리에서 가장 자주 사용되는 조건절에 맞는 인덱스를 설계해야 함
- 복합 인덱스 설계 시
- 카디널리티가 높은 컬럼을 인덱스의 가장 앞쪽에 배치하는 것이 일반적인 권장 사항
- 인덱스가 가장 먼저 가장 많은 양의 데이터를 효과적으로 필터링할 수 있도록 도움
(user_id, updated_at)복합 인덱스에서user_id의 카디널리티가updated_at보다 훨씬 높다면,user_id를 먼저 두는 것이 좋음
This post is licensed under CC BY 4.0 by the author.