주니어 백엔드 개발자가 반드시 알아야 할 실무 지식 - 3장 성능을 좌우하는 DB 설계와 쿼리
백엔드 성능 문제에서 가장 자주 병목이 되는 곳은 결국 DB다.
애플리케이션은 수평 확장이 비교적 쉽지만, DB는 잘못 설계되면 병목이 누적되기 쉽다.
이 장의 핵심
- 좋은 DB 설계는 단순히 정규화/비정규화 선택 문제가 아니다.
- 쿼리 패턴과 인덱스 전략이 실제 성능을 결정한다.
- 쿼리는 “문법적으로 맞는지”가 아니라 “어떻게 실행되는지”를 봐야 한다.
성능에 영향을 주는 설계 요소
1. 인덱스
인덱스는 조회 속도를 높이는 도구이지만, 동시에 쓰기 비용도 만든다.
- 읽기가 많은 컬럼에는 유리
- 쓰기가 많은 테이블에 과한 인덱스는 오히려 손해
- 복합 인덱스는 순서가 중요
주니어가 자주 하는 실수는 “조회가 느리니 컬럼마다 인덱스를 붙이는 것”이다.
실제론 쿼리 조건 순서, 정렬, 범위 조건 여부를 같이 봐야 한다.
2. 실행 계획
SQL은 동일해 보여도 실행 계획에 따라 성능이 크게 달라진다.
반드시 확인해야 할 것:
- index scan / full scan
- rows 예측 개수
- filesort 여부
- temporary table 사용 여부
- join 순서
3. 정규화와 비정규화
- 정규화는 데이터 정합성에 유리
- 비정규화는 조회 최적화에 유리
실무에서는 둘 중 하나만 택하기보다, 핵심 쓰기 경로는 정규화하고 조회 성능이 필요한 화면은 별도 read model이나 캐시로 보완하는 경우가 많다.
쿼리 작성 시 봐야 할 것
- 조건절에 인덱스를 탈 수 있는가
SELECT *가 정말 필요한가- 페이지네이션은 offset 기반으로 충분한가
- join이 정말 필요한가, 혹은 두 단계 조회가 더 나은가
- 한 번의 무거운 쿼리와 여러 번의 가벼운 쿼리 중 무엇이 적절한가
특히 자주 나오는 문제
느린 페이지네이션
OFFSET이 커질수록 뒤 페이지는 비싸다.
그래서 트래픽이 많거나 데이터가 큰 경우 cursor 기반 페이지네이션을 고려해야 한다.
N+1 문제
ORM을 쓰는 서비스에서 가장 흔한 성능 함정 중 하나다.
- 객체 그래프는 편리하지만
- 쿼리가 어떻게 나가는지 안 보면 성능이 무너진다
즉 ORM을 쓸수록 SQL을 더 알아야 한다.
락과 정합성
느린 쿼리는 단순히 응답 시간을 늘리는 데서 끝나지 않는다.
- 긴 트랜잭션
- lock wait
- deadlock
- 커넥션 고갈
같은 2차 문제를 만든다.
정리
DB 성능은 “쿼리를 몇 ms 줄였는가”보다
데이터 모델, 인덱스, 실행 계획, 트랜잭션 설계가 얼마나 맞물리는가의 문제다.
실무에서는 SQL을 잘 쓰는 사람보다,
어떤 데이터 접근 패턴이 어떤 비용을 만들지 예상할 수 있는 사람이 강하다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
댓글
아직 댓글이 없습니다