DB 인덱스, "그냥 걸면 빨라지는 거 아닌가요?"

TeamGrit·2025년 12월 21일

Interview-Question

목록 보기
9/12

안녕하세요, 이력서 기반 면접 준비를 도와드리는 QueryDaily 팀입니다.


"쿼리가 느린데요, 인덱스 걸어보세요."

개발하다 보면 한 번쯤 들어본 조언이죠. 그래서 인덱스를 걸었더니 정말 빨라졌습니다. 그런데 면접장에서 이런 질문이 날아옵니다.

"인덱스가 왜 빠른 건가요?"
"인덱스를 걸면 항상 좋은 건가요?"
"복합 인덱스에서 컬럼 순서가 왜 중요하죠?"
.
.
.
순간 머릿속이 하얘지는 경험, 다들 있으시죠?

오늘은 인덱스가 어떻게 동작하는지, 언제 써야 하고 언제 쓰면 안 되는지, 그리고 면접에서 자주 나오는 꼬리 질문까지 완벽하게 정리해 드리겠습니다.


인덱스란 무엇인가?

인덱스를 가장 쉽게 이해하는 방법은 책의 색인(Index)을 떠올리는 것입니다.

1000페이지짜리 책에서 "트랜잭션"이라는 단어를 찾는다고 가정해 봅시다. 색인 없이 찾으려면? 1페이지부터 1000페이지까지 전부 훑어봐야 합니다. 하지만 책 뒤에 있는 색인을 보면 "트랜잭션 - 324p, 512p, 789p"라고 적혀 있죠. 바로 해당 페이지로 이동할 수 있습니다.

데이터베이스 인덱스도 똑같습니다.

-- 인덱스 없이 조회 (Full Table Scan)
SELECT * FROM users WHERE email = 'test@example.com';
-- 100만 건의 데이터를 처음부터 끝까지 확인

-- 인덱스 있으면 (Index Scan)
-- 정렬된 인덱스에서 빠르게 위치를 찾아 바로 접근

인덱스는 어떻게 동작하는가? (B-Tree 구조)

대부분의 RDBMS(MySQL, PostgreSQL, Oracle)는 B-Tree(Balanced Tree) 구조로 인덱스를 구현합니다.

B-Tree의 특징

                    [50]
                   /    \
            [20, 30]    [70, 80]
            /  |  \      /  |  \
         [10][25][35] [60][75][90]
  • 항상 정렬된 상태를 유지합니다
  • 루트 노드에서 리프 노드까지의 거리가 동일합니다 (Balanced)
  • 데이터를 찾을 때 O(log N)의 시간 복잡도를 가집니다

100만 건의 데이터가 있다면:

  • Full Table Scan: 최악의 경우 100만 번 확인
  • B-Tree Index: 약 20번의 비교로 찾음 (log2(1,000,000) ≈ 20)

실제 인덱스 구조

MySQL InnoDB 기준으로 인덱스는 이렇게 구성됩니다:

[인덱스 키 값] -> [실제 데이터의 위치(PK 또는 Row ID)]
-- users 테이블에 email 인덱스가 있다면
CREATE INDEX idx_email ON users(email);

-- 인덱스 내부 구조 (개념적)
'alice@test.com'   -> PK: 1
'bob@test.com'     -> PK: 5
'charlie@test.com' -> PK: 3
-- (알파벳 순으로 정렬되어 저장)

인덱스가 항상 좋은 것은 아니다

여기서 많은 분들이 실수합니다. "느리면 인덱스"라는 공식을 맹신하는 거죠.

인덱스의 비용

1. 저장 공간 증가
인덱스도 데이터입니다. 테이블 크기의 10~30%가 추가로 필요합니다.

2. 쓰기 성능 저하
INSERT, UPDATE, DELETE가 발생하면 인덱스도 함께 갱신해야 합니다.

-- 인덱스가 5개인 테이블에 INSERT 하면?
-- 1. 테이블에 데이터 삽입
-- 2. 인덱스 1 갱신 (B-Tree 재정렬)
-- 3. 인덱스 2 갱신
-- 4. 인덱스 3 갱신
-- 5. 인덱스 4 갱신
-- 6. 인덱스 5 갱신

쓰기가 빈번한 테이블에 인덱스를 과도하게 걸면 오히려 전체 성능이 떨어집니다.

3. 인덱스를 타지 않는 경우

인덱스를 만들어도 사용되지 않는 경우가 있습니다:

-- 1. 인덱스 컬럼에 함수/연산 적용
SELECT * FROM users WHERE YEAR(created_at) = 2024;  -- 인덱스 사용 X
SELECT * FROM users WHERE created_at >= '2024-01-01'
                      AND created_at < '2025-01-01';  -- 인덱스 사용 O

-- 2. LIKE 검색에서 와일드카드가 앞에 오는 경우
SELECT * FROM users WHERE name LIKE '%홍길동';   -- 인덱스 사용 X
SELECT * FROM users WHERE name LIKE '홍길동%';   -- 인덱스 사용 O

-- 3. OR 조건 (각 컬럼에 개별 인덱스가 있어도)
SELECT * FROM users WHERE email = 'test@test.com' OR phone = '010-1234-5678';
-- 옵티마이저가 Full Scan이 더 효율적이라고 판단할 수 있음

-- 4. 데이터의 대부분을 조회하는 경우
SELECT * FROM users WHERE gender = 'M';
-- 전체의 50%를 조회한다면 Full Scan이 더 빠름

복합 인덱스와 컬럼 순서의 중요성

실무에서는 단일 컬럼 인덱스보다 복합 인덱스(Composite Index)를 더 많이 사용합니다.

CREATE INDEX idx_status_created ON orders(status, created_at);

복합 인덱스의 동작 원리

복합 인덱스는 첫 번째 컬럼을 기준으로 정렬한 뒤, 같은 값 내에서 두 번째 컬럼으로 정렬합니다.

(status, created_at) 인덱스 내부 구조:

'COMPLETED', '2024-01-01' -> PK: 10
'COMPLETED', '2024-01-02' -> PK: 15
'COMPLETED', '2024-01-03' -> PK: 8
'PENDING',   '2024-01-01' -> PK: 3
'PENDING',   '2024-01-02' -> PK: 22
'SHIPPED',   '2024-01-01' -> PK: 7

컬럼 순서가 중요한 이유

-- 인덱스: (status, created_at)

-- 1. 인덱스 사용 O
SELECT * FROM orders WHERE status = 'PENDING';
SELECT * FROM orders WHERE status = 'PENDING' AND created_at > '2024-01-01';

-- 2. 인덱스 사용 X (또는 비효율적)
SELECT * FROM orders WHERE created_at > '2024-01-01';

왜 두 번째 쿼리는 인덱스를 제대로 활용하지 못할까요?

인덱스가 status로 먼저 정렬되어 있기 때문입니다. created_at만으로 검색하면, 인덱스 전체를 훑어야 합니다. 마치 전화번호부에서 이름을 모른 채 전화번호만으로 찾는 것과 같습니다.

복합 인덱스 설계 원칙

1. 카디널리티(Cardinality)가 높은 컬럼을 앞에
   - 카디널리티 = 고유한 값의 개수
   - 성별(2) < 나이(100) < 이메일(100만)

2. 동등 조건(=)에 사용되는 컬럼을 범위 조건(<, >, BETWEEN) 앞에

3. 자주 사용되는 조합을 기준으로 설계

클러스터드 인덱스 vs 논클러스터드 인덱스

MySQL InnoDB를 사용한다면 반드시 알아야 할 개념입니다.

클러스터드 인덱스 (Clustered Index)

  • 테이블당 하나만 존재합니다
  • 실제 데이터가 인덱스 순서대로 물리적으로 정렬됩니다
  • InnoDB에서는 PK가 자동으로 클러스터드 인덱스가 됩니다
-- PK = 클러스터드 인덱스
CREATE TABLE users (
    id BIGINT PRIMARY KEY,  -- 이 순서대로 데이터가 물리적으로 저장됨
    email VARCHAR(255),
    name VARCHAR(100)
);

논클러스터드 인덱스 (Non-Clustered Index / Secondary Index)

  • 여러 개 생성 가능합니다
  • 인덱스에는 키 값 + PK 값이 저장됩니다
  • 실제 데이터를 찾으려면 PK로 한 번 더 조회해야 합니다
CREATE INDEX idx_email ON users(email);

-- email로 검색하면?
-- 1단계: idx_email에서 email 검색 -> PK 값 획득
-- 2단계: PK로 클러스터드 인덱스 검색 -> 실제 데이터 획득

이 두 번의 조회를 줄이기 위해 커버링 인덱스를 활용하기도 합니다.

커버링 인덱스 (Covering Index)

쿼리에 필요한 모든 컬럼이 인덱스에 포함되어 있으면, 테이블에 접근하지 않고 인덱스만으로 결과를 반환할 수 있습니다.

-- 인덱스: (status, created_at, amount)
CREATE INDEX idx_covering ON orders(status, created_at, amount);

-- 커버링 인덱스 활용 (테이블 접근 없이 인덱스만 조회)
SELECT status, created_at, amount
FROM orders
WHERE status = 'PENDING';

-- 커버링 인덱스 활용 불가 (user_id가 인덱스에 없음)
SELECT status, created_at, amount, user_id
FROM orders
WHERE status = 'PENDING';

실행 계획에서 Using index가 표시되면 커버링 인덱스가 적용된 것입니다.

면접 예상 질문

Q1. "인덱스를 무조건 많이 걸면 좋은 건가요?"

핵심 답변: 아닙니다. 인덱스는 읽기 성능을 높이지만, 쓰기 성능을 저하시킵니다. INSERT/UPDATE/DELETE 시 인덱스도 함께 갱신해야 하기 때문입니다. 또한 저장 공간도 추가로 필요합니다. 따라서 조회 패턴을 분석하여 꼭 필요한 인덱스만 생성해야 합니다.

Q2. "인덱스를 걸었는데 안 타는 경우가 있나요?"

핵심 답변: 네, 여러 경우가 있습니다. 인덱스 컬럼에 함수나 연산을 적용한 경우, LIKE 검색에서 와일드카드가 앞에 오는 경우, 데이터의 대부분을 조회하여 옵티마이저가 Full Scan이 더 효율적이라고 판단한 경우 등이 있습니다.

Q3. "복합 인덱스에서 컬럼 순서는 왜 중요한가요?"

핵심 답변: 복합 인덱스는 첫 번째 컬럼을 기준으로 정렬되고, 같은 값 내에서 두 번째 컬럼으로 정렬됩니다. 따라서 WHERE 절에서 첫 번째 컬럼이 조건에 포함되지 않으면 인덱스를 효율적으로 사용할 수 없습니다.

Q4. "클러스터드 인덱스와 논클러스터드 인덱스의 차이는?"

핵심 답변: 클러스터드 인덱스는 테이블당 하나만 존재하며, 실제 데이터가 인덱스 순서대로 물리적으로 정렬됩니다. InnoDB에서는 PK가 클러스터드 인덱스입니다. 논클러스터드 인덱스는 여러 개 생성 가능하며, 인덱스에 키 값과 PK가 저장되어 있어 실제 데이터 조회 시 PK로 한 번 더 접근해야 합니다.

Q5. "PK를 auto_increment로 하는 이유가 있나요?"

핵심 답변: InnoDB에서 PK는 클러스터드 인덱스이므로, PK 순서대로 데이터가 물리적으로 저장됩니다. auto_increment를 사용하면 새 데이터가 항상 테이블 끝에 추가되어 페이지 분할이 최소화됩니다. 반면 UUID처럼 무작위 값을 PK로 사용하면 데이터 삽입 위치가 랜덤해져 페이지 분할이 빈번하게 발생하고 성능이 저하됩니다.

마무리

오늘 배운 내용을 정리하면 이렇습니다:

  • 인덱스는 B-Tree 구조로 O(log N) 탐색을 가능하게 합니다
  • 인덱스는 읽기 성능 향상, 하지만 쓰기 성능 저하저장 공간 증가라는 트레이드오프가 있습니다
  • 복합 인덱스의 컬럼 순서는 쿼리 패턴에 맞춰 신중하게 설계해야 합니다
  • 클러스터드 인덱스와 논클러스터드 인덱스의 차이를 이해하면 쿼리 최적화에 큰 도움이 됩니다

면접에서 인덱스를 물어보는 이유는 단순히 "CREATE INDEX를 할 줄 아는가"가 아닙니다. 내부 동작 원리를 이해하고, 상황에 맞는 최적의 인덱스 전략을 설계할 수 있는지를 확인하기 위함입니다.

이력서에 적힌 'MySQL 사용 경험' 한 줄에서 시작될 수 있는 수많은 꼬리 질문들,
QueryDaily 와 함께 미리 대비해 보세요.


👉 팀그릿 더 알아보기

tags: Database Index MySQL 성능최적화 백엔드면접

profile
우리는 당신의 가능성을 믿는 사람들입니다. '되는 사람'이 되는 방법을 이야기합니다.

1개의 댓글

comment-user-thumbnail
2026년 1월 4일

좋은 글 감사합니다.

답글 달기