
SQL 인덱스는 데이터베이스 성능 이야기를 할 때 가장 먼저 나오는 주제입니다. 특히 B-tree 구조를 함께 떠올리면 어떤 쿼리에 효과가 있고 어떤 쿼리에 효과가 적은지 판단하기 쉬워집니다.
핵심은 테이블 전체를 읽기 전에 찾을 범위를 줄일 수 있는가입니다. 이 글은 PostgreSQL과 MySQL 공식 문서를 기준으로 B-tree 인덱스, WHERE 조건, ORDER BY에서의 기본 판단 기준을 정리합니다.

인덱스를 먼저 한 줄로 정리하면
인덱스는 테이블 데이터를 다른 순서와 구조로 보조 저장해 두고, 필요한 행을 더 적게 읽도록 돕는 자료구조입니다. 책 뒤의 찾아보기와 비슷하지만, 데이터베이스에서는 훨씬 엄격한 비용 계산이 함께 일어납니다.
CREATE INDEX idx_orders_user_id
ON orders (user_id);
SELECT *
FROM orders
WHERE user_id = 42;위 쿼리는 `user_id` 조건으로 찾을 행을 좁힐 수 있으므로 인덱스가 도움이 될 가능성이 큽니다.
B-tree를 떠올리면 SQL 인덱스가 이해된다
많은 관계형 데이터베이스에서 기본 인덱스는 B-tree 계열입니다. B-tree는 값이 정렬된 구조를 유지하므로 특정 값 탐색뿐 아니라 범위 조건에도 잘 맞습니다.
- `user_id = 42`처럼 같은 값을 찾는 조건
- `created_at >= ‘2026-01-01’`처럼 범위를 찾는 조건
- `ORDER BY created_at`처럼 정렬 순서를 활용할 수 있는 경우
반대로 조건이 인덱스 순서를 활용하지 못하거나 읽어야 할 행이 너무 많으면 기대만큼 빨라지지 않을 수 있습니다.
WHERE 조건은 선택도가 중요하다
선택도는 조건이 얼마나 많은 행을 걸러내는지에 가까운 감각입니다. 전체 100만 행 중 100행만 찾는 조건은 인덱스 효과가 크지만, 90만 행을 읽어야 하는 조건은 full scan이 더 나을 수 있습니다.
-- 효과가 클 가능성이 있는 조건
WHERE order_id = 10001
-- 값 분포에 따라 효과가 작을 수 있는 조건
WHERE status = 'ACTIVE'status처럼 값 종류가 적은 컬럼도 상황에 따라 인덱스가 유용할 수 있지만, 단순히 값 종류가 적다는 이유만으로 항상 좋은 선택은 아닙니다. 실제 데이터 분포와 실행 계획을 함께 봐야 합니다.
ORDER BY에서도 인덱스 순서가 중요하다
인덱스가 이미 특정 순서로 정렬되어 있다면 데이터베이스는 별도 정렬 작업을 줄일 수 있습니다. 특히 WHERE 조건과 ORDER BY가 같은 인덱스 흐름에 맞을 때 효과가 커집니다.
CREATE INDEX idx_orders_user_created
ON orders (user_id, created_at);
SELECT *
FROM orders
WHERE user_id = 42
ORDER BY created_at DESC;복합 인덱스에서는 컬럼 순서가 중요합니다. 어떤 조건이 먼저 범위를 좁히고 어떤 순서로 정렬할지 쿼리 패턴을 보고 설계해야 합니다.
실무 체크리스트
- 자주 실행되는 실제 쿼리부터 확인한다
- WHERE 조건이 충분히 많은 행을 줄이는지 본다
- ORDER BY, GROUP BY와 인덱스 순서가 맞는지 검토한다
- INSERT, UPDATE 비용과 저장 공간 증가도 함께 고려한다
- EXPLAIN으로 full scan, index scan, 읽은 행 수를 확인한다
정리
B-tree를 이해할 때는 문법이나 기능 이름보다 문제가 생기는 경계를 먼저 보는 편이 좋습니다. 오늘 글의 기준은 ‘언제 다시 실행되고, 어디까지 공개되고, 어떤 권한이 남는가’처럼 실수 지점을 분리하는 것입니다.
함께 보면 좋은 내부 글은 JPA N+1 문제는 왜 생길까, JPA fetch join과 Pageable을 같이 쓰면 왜 위험할까, Spring Boot @Transactional은 어디에 붙여야 할까입니다. 외부 기준은 PostgreSQL Docs – Indexes, PostgreSQL Docs – B-Tree Indexes, SQLite Query Planner를 확인했습니다.