데이터 베이스/데이터베이스 기본

Ch07. 인덱스 - 인덱스가 필요한 이유

webmaster 2026. 6. 4. 22:14

우리 쇼핑몰이 대성공을 거두어, 판매하는 상품 수가 25개가 아니라 50 , 100 개로 늘어났다고 상상해 보자.

 

이제 고객이 우리 쇼핑몰에서 "게이밍 노트북"을 검색한다. 우리 시스템은 데이터베이스에 다음의 쿼리를 실행할 것이다.

select * from items where item_name = '게이밍 노트북';

 

데이터가 없었을 때는 깜짝할 사이에 끝나던 쿼리가, 이제는 3, 5, 혹은 이상이 걸리기 시작한다. 서비스 속도가 느려지고 고객들은 답답함을 느껴 떠나간다. 분명 쿼리는 똑같은데, 이렇게 느려진 걸까? 데이터베이스 안에서 도대체 무슨 일이 벌어지고 있는 걸까?

 

느린 검색의 원인: 테이블 스캔 (Full Table Scan)

인덱스가 없는 테이블에서 특정 데이터를 찾는 과정은, 비유하자면 100 페이지짜리 거대한 책에서 특정 단어 하나를 찾기 위해, 책의 페이지부터 마지막 페이지까지 넘겨보는 같다.

 

데이터베이스는 "item_name" 컬럼에 "게이밍 노트북"이라는 값이 어디에 있는지 있는 아무런 "힌트"가 없다. 그래서 데이터베이스는 가장 무식하고 정직한 방법을 선택한다. 바로  "items" 테이블 전체를 디스크에서 메모리로 읽어 들인 , 번째 행부터 마지막 100 번째 행까지 하나씩 차례대로 "item_name" 컬럼의 값을 비교하는 것이다.

Item Table(일부 결과 생략)

  • 이러한 작업 방식을 풀 테이블 스캔(Full Table Scan)이라고 부른다.
  • 최선의 경우: 우리가 찾는 데이터가 우연히 번째 행에 있다면 번의 비교만으로 끝난다.
    • ) 무선 기계식 키보드
  • 최악의 경우: 우리가 찾는 데이터가 마지막 행에 있거나, 아예 존재하지 않는다면 100 번의 비교를 모두 수행해야만 결과를 있다.

테이블 스캔은 빅오 표기법으로 "O(n)"으로 표현한다. 여기서 "n"은 레코드 건수를 나타내며, 레코드 수가 배로 증가하면 스캔 시간도 대략 배로 증가한다는 의미다. 쉽게 이야기해서 테이블 스캔은 데이터 수 만큼 데이터를 탐색해야 한다는 뜻이다.

 

이렇듯 테이블 스캔에서 데이터가 많아질수록 검색 시간이 정비례해서 늘어나는 것은 당연한 결과다. 이것이 바로 우리의 서비스가 느려진 근본적인 원인이다. 이런 방식을 계속 유지한다면 우리 서비스는 장사가 되면 될수록, 그래서 데이터가 많아 질 수록 점점 느려지게 된다. 나중에는 사용자들이 답답해서 우리 서비스를 찾지 않게 것이다. 이러한 성능 문제는 반드시 해결해야 한다.

 

데이터 양에 따른 성능 저하

데이터 양에 따른 정확한 응답시간을 예측하는 것은 거의 불가능하다. 왜냐하면 응답시간은 데이터베이스 서버의 사양(CPU, 메모리, 디스크 I/O 성능), 환경 설정, 데이터의 행(Row)당 크기, 시스템의 현재 부하 수많은 변수에 따라 크게 달라지기 때문이다.

 

하지만 일반적인 기업용 서버 환경(SSD 디스크 기반) 가정하고, 행당 1KB 데이터를 가진 테이블 기준으로 대략적인 예상 응답시간을 정리하면 다음과 같다.

데이터 건수 데이터 크기 (행당 1KB 가정) 예상 응답시간  비고
100만 건 약 1GB 수 초(예: 0.2 ~ 3초) 디스크 I/O 속도에 따라 우되며, 메모리(버퍼 캐시) 데이터가 일부라도 있으 빨라짐
1,000만 건 약 10GB 수 초 ~ 1분 내외(예:2초 ~ 30초) 본격적으로 디스크 I/O 목이 발생하기 시작하는
1억 건 약 100GB 수십 초 이상  (예: 20초 ~ 5분) 다른 작업과 경합이 발생할 경우 응답시간은 예측하기 어려울 정도로 길어질 있다.

표는 단순 참고용이며, 실제 환경에서는 이상 차이가 있다.

  • 실무에서는 본인 환경에 맞는 성능 테스트를 통해 성능을 확인해야 한다.
  • 실제로는 수많은 요청을 동시에 처리한다. 예를 들어서 10명의 사용자가 동시에 요청하면 풀테이블 스캔도 10개가 동시에 발생할 있다. 이런 경우 성능은 훨씬 느려진다.

 

 

실무 이야기

1) 오늘날의 사용자들은 초의 로딩 시간도 기다리지 않는다.

  • 일반적인 서비스를 생각해 보자. 하나의 화면에 단순히 "items" 테이블 하나만 조회할까? 아니다. 보통 한 화면을 보여주기 위해서는 다양한 데이터가 필요하다.
  • 따라서 다양한 테이블들을 함께 조회한다.
  • 테이블들이 모두 테이블 캔이라면 데이터의 양이 적을 때는 문제가 없어 보이겠지만, 데이터가 점점 증가하기 시작하는 순간 서비스도 점점 느려지며 많은 사용자들이 이탈할 것이다.

2) 풀테이블 스캔은 매우 비용이 높은 작업이므로, 서비스의 핵심 기능에서 가급적 풀테이블 스캔이 발생하지 않도록 설계하는 것은 필수다.

  • 인덱스 활용: "WHERE" 절에 자주 사용되는 검색 조건 컬럼에는 인덱스(Index)를 생성하여 풀테이블 스캔을 방지하는 것이 가장 기본적인 해결책이다.
  • 실행 계획 확인: 쿼리 실행 실행 계획(Execution Plan) 확인하여 의도치 않은 풀테이블 스캔이 발생하는지 반드시 점검해야 한다.
  • 작업 시간 분리: 대용량 데이터에 대한 전체 스캔이 불가피한 통계/배치 작업이라면, 서비스 이용자가 적은 새벽 시간에 실행하는 것을 권장한다