데이터베이스

Full Scan'은 용납 못 해! 느린 쿼리 퇴치를 위한 EXPLAIN 활용법🔥

JihwanGo 2025. 9. 7. 22:29
반응형

인덱스? 전 이렇게 생각합니다.

처음 개발을 시작할 때, 인덱스는 그냥 "쿼리를 빠르게 해주는 것" 정도로만 알고 있었어요. 그런데 서비스에 데이터가 몇백만, 몇천만 건씩 쌓이면서 '느린 쿼리' 하나가 시스템 전체를 마비시킬 수 있다는 걸 몸으로 깨달았죠. 그때부터 인덱스는 저에게 단순히 지식이 아니라, 서비스의 생존을 결정하는 중요한 무기가 되었습니다.

인덱스를 한마디로 설명하면 '탐색을 위한 지름길' 입니다. 마치 거대한 창고에서 물건(데이터)을 찾을 때, 모든 물건을 다 뒤지는 대신(Full Table Scan), 정리된 목록(인덱스)을 보고 바로 달려가는 것과 같죠. 복잡한 B-Tree 구조를 다 외울 필요는 없어요. 그냥 '아, 이게 정렬된 트리 구조로 데이터를 빠르게 찾아주는구나' 정도만 이해해도 충분합니다.


내가(현업 개발자.....탈출 하고 싶다...)가 쓰는 인덱스 튜닝 3가지 꿀팁

1. 모든 쿼리에는 습관처럼 EXPLAIN을 붙여라

저는 새로운 쿼리를 만들거나 기존 쿼리 성능을 개선할 때 가장 먼저 하는 일이 있습니다. 바로 쿼리 앞에 EXPLAIN을 붙여서 데이터베이스의 실행 계획을 확인하는 거죠. 이건 개발자에게 가장 중요한 습관이라고 생각합니다.

- SQL
-- 쿼리가 느릴 때, 먼저 이걸 실행해 보세요.
EXPLAIN SELECT * FROM users WHERE email = 'testuser@example.com';

EXPLAIN 결과를 보면 Seq Scan이나 Full Table Scan 같은 단어가 보일 때가 있어요. 이게 바로 빨간불입니다. "아, 데이터베이스가 인덱스를 못 쓰고 전체 테이블을 다 뒤지고 있구나" 하고 바로 알아채야 합니다. 이때 email 컬럼에 인덱스를 만들고 다시 EXPLAIN을 해보면 Index Scan으로 바뀌는 마법을 볼 수 있습니다.

2. 복합 인덱스, 순서를 전략적으로 정하라

실제 서비스에서는 AND나 OR 조건으로 여러 컬럼을 동시에 검색하는 일이 흔합니다. 예를 들어, '특정 지역의 완료된 주문'을 찾을 때처럼요. 이때는 복합 인덱스가 필수입니다.

- SQL
-- 복합 인덱스 생성
CREATE INDEX idx_orders_city_status ON orders(city, status);

여기서 제 경험상 중요한 팁! 복합 인덱스에서는 컬럼 순서가 매우 중요합니다. 제 경우, WHERE 절에 가장 자주 사용되거나, 데이터 중복이 적은(카디널리티가 높은) 컬럼을 맨 앞에 둡니다. 위 예시처럼 city와 status가 있다면, 보통 city가 훨씬 다양하니 city, status 순서로 만드는 게 좋습니다. status만으로 검색할 때 인덱스가 작동하지 않는다는 것을 항상 기억해야 합니다.

3. 특별한 문제를 해결하는 인덱스, 다 알고 있나요?

주니어 때는 몰랐지만, 시니어가 될수록 이런 특수한 인덱스들이 문제를 한 방에 해결해 주는 경우가 많다는 것을 깨닫습니다.

  • 부분 인덱스 (Partial Index): 저희는 종종 '활성 사용자'만 찾는 쿼리를 씁니다. 전체 회원 중 10%만 활성 사용자라면, 굳이 100%에 인덱스를 걸 필요가 없겠죠?이렇게 하면 인덱스 크기도 줄고, 성능도 훨씬 빨라집니다.
  • SQL
    -- active 상태인 사용자에게만 인덱스 생성
    CREATE INDEX idx_users_active_id ON users(id) WHERE status = 'active';
    
  • 표현식 인덱스 (Expression Index): 가끔 개발하다 보면 WHERE LOWER(email) = '...' 처럼 함수를 사용해 검색해야 할 때가 있어요. 이럴 때 일반 인덱스는 소용이 없습니다.이런 인덱스를 만들면 함수를 사용해도 인덱스가 작동합니다.
  • SQL
    -- 함수 결과에 인덱스 생성
    CREATE INDEX idx_users_email_lower ON users(LOWER(email));
    
  • 커버링 인덱스 (Covering Index): 쿼리에서 필요한 모든 데이터가 인덱스 안에 다 들어있어서, 실제 테이블까지 가서 데이터를 읽을 필요가 없는 인덱스입니다. EXPLAIN 결과에 Index-Only Scan이 보이면 이게 바로 커버링 인덱스가 잘 작동하고 있다는 뜻입니다.

마무리: 결국 튜닝은 '관심'입니다.

결론적으로, 인덱스 튜닝은 '어떤 쿼리가 느릴까?' 에 대한 끊임없는 관심에서 시작됩니다. 저는 매일 아침 성능 모니터링 대시보드를 확인하고, 느린 쿼리가 보이면 바로 EXPLAIN을 실행해보는 습관을 들였습니다.

이 글이 여러분의 개발 인생에 작은 도움이 되었으면 좋겠습니다. 혹시 지금 작업 중인 쿼리 중에 느린 게 있다면, EXPLAIN부터 쳐보는 건 어떨까요?

반응형