[CS/데이터베이스] 인덱스의 원리 및 대규모 데이터 최적화 전략

선우·2025년 12월 26일

CS

목록 보기
13/20

[CS/데이터베이스] 05. 인덱스의 원리 및 대규모 데이터 최적화 전략

⚡ 한 줄 요약: 인덱스는 B+Tree 자료구조를 활용해 데이터 조회 성능을 극대화하는 '지름길'이며, 쓰기 비용과의 트레이드오프와 물리적/논리적 분산 전략을 이해하는 것이 성능 최적화의 핵심입니다.

1. 👋 들어가며: "내 API는 왜 대량의 데이터 앞에서 느려질까?"

수천, 수만 개의 데이터를 다루는 다중 필터나 무한 스크롤을 구현하다 보면, 특정 조건에서 API 응답이 현저히 느려지는 경험을 하게 됩니다.

단순히 "데이터가 많아서"라고 넘기기엔 엔지니어로서 아쉬움이 남죠.

그 해답의 90%는 바로 인덱스(Index)에 있습니다.

  • 🧐 Why:
    • 인덱스는 단순히 "조회를 빠르게 하는 도구"를 넘어, 데이터베이스가 데이터를 물리적으로 어떻게 저장하고 탐색하는지에 대한 설계 철학을 담고 있기 때문입니다.
  • 🎯 Goal:
    • 클러스터형과 비클러스터형 인덱스의 구조적 차이를 마스터합니다.
    • 현대 DB의 표준인 B+Tree 자료구조가 왜 범위 검색에 유리한지 이해합니다.
    • 복합 인덱스 설계 시 '컬럼 순서'가 실행 계획에 미치는 영향을 파악합니다.
    • 샤딩과 파티셔닝을 통한 물리적/논리적 최적화 기법을 구분합니다.

📂 2. 인덱스(Index)

📌 2-1. 인덱스(Index)란?

인덱스는 데이터베이스의 검색 속도를 향상시키기 위해 목차와 같이 데이터를 정리해둔 자료구조입니다.

도서관에서 원하는 책을 찾는 상황을 떠올려 보세요.
책 제목을 하나하나 다 확인하면서 찾는다면 시간이 너무 오래 걸리겠죠?

하지만 목차나 서가 번호 분류표를 보고 가면 원하는 위치로 바로 갈 수 있습니다.
데이터베이스의 인덱스가 바로 이 목차와 분류표의 역할을 합니다.

인덱스가 없다면 컴퓨터는 데이터를 찾기 위해 처음부터 끝까지 다 뒤져야 하는 풀 스캔(Full Scan)을 해야 하지만, 인덱스를 잘 활용하면 필요한 데이터만 빠르게 뽑아낼 수 있습니다.

📌 2-2. 클러스터형 인덱스 (Clustered Index)

클러스터형 인덱스는 데이터 자체가 인덱스 순서대로 정렬되어 저장되는 방식입니다.

  • 물리적 정렬

    • 테이블의 모든 열이 기본 키(Primary Key) 값을 기준으로 물리적으로 정렬됩니다.
  • 특징

    • 테이블당 딱 하나만 존재할 수 있습니다.
  • 성능

    • 데이터를 뒤죽박죽 섞인 상태(인덱스 미적용)에서 999번을 찾으려면 하나하나 확인해야 하지만, 클러스터형 인덱스가 있으면 정렬된 상태이므로 999번의 위치를 즉시 계산해서 점프할 수 있습니다.
  • 데이터를 미리 정렬해두어 조회 시 압도적인 속도를 내는 것이 핵심입니다.

📌 2-3. 비클러스터형 인덱스 (Non-Clustered Index)

비클러스터형 인덱스는 원래 테이블의 순서는 건드리지 않고, 특정 컬럼별로 정렬된 별도의 '인덱스 테이블'을 만드는 방식입니다.

  • 별도 테이블 생성

    • 위 그림처럼 '이름(name)'을 기준으로 정렬된 별도의 인덱스 테이블이 생성됩니다.
  • 조회 방식

    1. 인덱스 테이블에서 '이영희'를 빠르게 찾습니다.
    2. 그곳에 기록된 PK(기본 키)값을 확인합니다.
    3. 알아낸 PK 값을 가지고 실제 데이터가 있는 원래 테이블로 이동하여 전체 데이터를 가져옵니다.
  • 특징

    • 원래 테이블을 변경하지 않으므로 한 테이블에 여러 개를 생성할 수 있습니다.
  • 실제 데이터를 찾으려면 반드시 PK를 통해 이동해야 하므로, 클러스터형 인덱스(PK 정렬)가 설정되어 있다는 전제가 필요합니다.

  • 그래서, 비클러스터형 인덱스를 보조 인덱스라고도 부릅니다.

📌 2-4. 헷갈리기 쉬운 포인트 / 오해 정리

  • 비클러스터형 인덱스가 많을수록 좋은 것 아닌가요?

    • 아닙니다. 인덱스 테이블을 추가로 만드는 것이므로 저장 공간을 차지하고, 데이터가 추가/수정될 때마다 인덱스 테이블도 같이 업데이트해야 하므로 과도한 생성은 오히려 성능을 저하시킵니다.
  • 왜 클러스터형은 하나만 만들 수 있나요?

    • 데이터를 물리적으로 한 줄로 세우는 방식이기 때문입니다.
    • 키(Key)기준과 이름 기준으로 동시에 정렬해서 저장할 수는 없으니까요.

📌 2-5. 한 줄 정리

  • 클러스터형 인덱스는 실제 데이터를 PK 순으로 물리 정렬하는 방식이고, 비클러스터형은 별도의 정렬된 인덱스 표에서 PK를 찾아 실제 데이터로 접근하는 방식입니다.

📂 3. 인덱스의 자료구조 (1) - B-Tree

📌 3-1. B-Tree

B-Tree는 데이터를 여러 노드로 분할해 저장하고, 단계별로 범위를 좁혀가며 O(logN)O(\log N)의 속도로 데이터를 찾아내는 자료구조입니다.

데이터베이스 인덱스는 검색 성능을 높이기 위해 특정한 자료구조를 사용하는데, 그 대표적인 것이 바로 B-Tree입니다.

핵심 동작 원리

  1. 노드와 데이터의 구성

    • B-Tree 구조를 보면 각 노드 아래에 특정한 표시들이 달려 있는 것을 볼 수 있습니다.

    • 이 표시가 바로 실제 데이터를 가리키는 포인터입니다.

    • 노드에 적혀 있는 숫자는 데이터의 PK(기본 키)를 의미합니다.

  2. 분할 저장의 이유

    • 데이터를 한곳에 모아두지 않고 여러 블록(노드)으로 분할하여 저장하는 이유는 오직 조회 속도를 높이기 위해서입니다.

    • 전체 데이터를 처음부터 끝까지 훑는 대신, 필요한 구간만 골라내기 위함입니다.

  1. 단계적 탐색 과정

    • 찾고자 하는 ID 값과 각 노드가 담고 있는 ID 값을 비교합니다.

    • 루트 노드부터 시작해 노드 안에 있는 키들을 쭉 훑어보고, 해당 PK 구간을 관리하는 자식 노드로 내려갑니다.

    • 예를 들어 ID=40을 찾는다면, 루트 노드(30)를 보고 "30보다 크니 오른쪽으로 가자"고 판단하여 범위를 좁힙니다.

    • 중간 노드(50, 80)에 도달하면 "50보다 작으니 왼쪽 리프 노드로 가자"고 다시 한번 범위를 좁힙니다.

이처럼 단계적으로 범위를 좁혀가며 탐색하면, 수만 건의 데이터 사이에서도 단 몇 번의 이동만으로 원하는 데이터에 도달할 수 있습니다.

📌 3-2. 헷갈리기 쉬운 포인트 / 오해 정리

  • 데이터는 마지막(리프) 노드에만 있나요?

    • 아니요, B-Tree는 루트 노드와 중간 노드를 포함한 모든 노드에 데이터(또는 데이터를 가리키는 포인터)가 저장됩니다.

    • 어떤 노드에서든 찾는 값이 있다면 바로 데이터를 반환할 수 있는 구조입니다.

  • 항상 정렬되어 있어야 하나요?

    • 그렇습니다. B-Tree의 핵심은 PK 값을 기준으로 노드 내의 키들이 정렬되어 있어야 한다는 것입니다.
    • 정렬이 되어 있어야만 "크다", "작다"를 비교하여 자식 노드로 내려갈 방향을 결정할 수 있기 때문입니다.

📌 3-3. 한 줄 정리

  • B-Tree는 모든 노드에 데이터를 품고 있으며, PK 비교를 통해 탐색 범위를 단계적으로 좁혀나가 데이터에 도달하는 효율적인 인덱스 구조입니다.

💻 참고

실무에서는 B-Tree의 모든 노드에 데이터가 있는 특징 때문에 노드의 크기가 커지면 디스크 I/O 효율이 떨어지는 단점을 고민하게 됩니다.

그래서 현대의 많은 데이터베이스는 이를 개선해 데이터는 리프 노드에만 몰아두고 노드 간 연결성을 강화한 B+Tree를 실제 인덱스 구조로 더 많이 채택하고 있습니다.


📂 4. 인덱스의 자료구조 (2) - B+Tree

📌 4-1. 현대 DB 인덱스의 표준 자료구조

B-Tree의 범위 검색 취약점을 보완하기 위해 데이터는 리프 노드에만 저장하고, 이들을 연결 리스트로 묶은 최적화된 자료구조입니다.

B-Tree는 모든 노드에 데이터를 품고 있어 특정 값을 찾는 데는 유리하지만, 여러 데이터를 찾는 범위 검색(Range Search)을 할 때는 효율이 떨어집니다.

데이터를 하나 찾을 때마다 다시 루트 노드부터 내려가야 하는 비효율이 발생하기 때문입니다.

이를 해결한 것이 바로 B+Tree입니다.

📌 4-2. B+Tree의 핵심 동작 원리

  1. 데이터 저장의 선택과 집중

    • B+Tree 핵심은 데이터가 루트 노드와 중간 노드에는 존재하지 않고 오직 리프 노드에만 존재한다는 점입니다.
  2. 길잡이 역할의 상위 노드

    • 그렇다고 상위 노드들이 노는 건 아닙니다.

    • 각각의 노드에 키 값은 존재하기 때문에, 검색 시 어디로 내려가야 할지 알려주는 길잡이 역할은 그대로 수행합니다.

  3. 검색 프로세스

    • 찾고자 하는 값과 루트 노드의 키 값을 비교합니다.

    • 값이 같거나 크면 오른쪽으로 이동하는 식으로 단계적으로 내려갑니다.

    • 실제 데이터는 상위에 없으므로, 무조건 리프 노드까지만 이동해야만 원하는 데이터를 얻을 수 있습니다.

  4. 리프 노드의 연결성

    • 모든 리프 노드들은 연결 리스트(Linked List) 형태로 서로 묶여 있습니다.

📌 4-3. 헷갈리기 쉬운 포인트 / 오해 정리

  • 상위 노드에는 데이터가 없으니 더 느린 것 아닌가요?

    • 데이터를 얻으려면 리프까지 가야 하니 개별 탐색은 조금 더 걸릴 수 있지만, 상위 노드에 데이터를 안 담는 만큼 하나의 노드에 더 많은 키 값을 담을 수 있습니다.

    • 이는 트리의 높이를 낮추는 결과로 이어져 전체적인 검색 성능을 안정화합니다.

  • B-Tree도 연결 리스트만 있으면 똑같은 것 아닌가요?

    • B-Tree는 데이터가 모든 노드에 흩어져 있어 연결 리스트만으로 해결되지 않습니다.

    • 모든 데이터를 리프 노드로 몰아넣은 B+Tree의 구조적 특징이 전제되어야 범위 검색 최적화가 가능합니다.

📌 4-4. 한 줄 정리

  • B+Tree는 데이터를 리프 노드에만 집중시키고 이들을 연결 리스트로 묶어, 범위 검색 효율과 디스크 I/O 성능을 극대화한 인덱스 최적화 구조입니다.

📂 5. 인덱스의 내부구조

📌 5-1. 클러스터형 인덱스의 내부 구조(B+Tree)

클러스터형 인덱스는 데이터 자체가 인덱스의 리프 노드에 포함되어 정렬된 구조입니다.

클러스터형 인덱스는 데이터 저장 방식 그 자체를 결정합니다.
B+Tree 구조를 따라가면 리프 노드에 도달하게 되는데, 여기서 실제 데이터를 바로 만날 수 있는 것이 핵심입니다.

  • 물리적 정렬

    • 리프 노드에 실제 데이터가 저장되며, 기본 키(PK)인 ID 값 순서대로 물리적으로 정렬되어 있습니다.
  • 직접 접근

    • 인덱스를 따라 데이터를 찾으면 추가적인 참조 없이 그 자리에서 바로 전체 데이터를 읽을 수 있습니다.
  • 구조 예시

    • ID=40인 데이터를 찾을 때, 루트(30)와 중간 노드(50, 80)를 거쳐 해당 리프 노드에 도착하면 그 행의 모든 정보(이름, 가격 등)를 즉시 획득합니다.

📌 5-2. 비클러스터형 인덱스의 내부 구조(B+Tree)

비클러스터형 인덱스는 실제 데이터가 아닌 '데이터의 주소(PK)'를 담고 있는 별도의 인덱스 테이블입니다.

비클러스터형 인덱스는 실제 데이터와 인덱스가 별도의 공간에 저장됩니다.
따라서 데이터를 찾는 과정이 한 단계 더 추가됩니다.

  • 리프 노드의 정체

    • 비클러스터형 인덱스의 리프 노드에서 만나는 것은 실제 데이터가 아니라 인덱스 테이블입니다.

    • 이 테이블은 인덱스로 지정한 컬럼(예: name)과 해당 행의 PK 값으로 구성됩니다.

  • 간접 접근 (2단계 탐색)

    1. 트리 구조를 통해 리프 노드에 도달하여 인덱스 테이블에서 특정 행을 찾습니다.
    2. 여기서 얻은 ID(PK) 값을 가지고, 다시 클러스터형 인덱스(원래 테이블)로 돌아가 실제 데이터를 조회합니다.
  • 구조 예시

    • 'name' 컬럼에 인덱스가 걸려 있다면, 리프 노드에서 '박민수'를 찾아 ID=4라는 정보를 얻고, 다시 이 ID로 실제 데이터를 가져오는 식입니다.

📌 5-3. 헷갈리기 쉬운 포인트 / 오해 정리

  • 비클러스터형은 독립적으로 존재할 수 있나?

    • 아닙니다. 비클러스터형 인덱스는 최종적으로 PK를 통해 원래 데이터를 찾아가야 하므로, 클러스터형 인덱스가 설정되어 있다는 전제하에 동작합니다.

    • 그래서 이를 '보조 인덱스'라고 부르기도 합니다.

  • 모든 인덱스는 리프 노드까지 가야 하나?

    • B+Tree 구조에서는 루트나 중간 노드에는 데이터가 없고 키 값(길잡이)만 있기 때문에, 원하는 데이터를 얻으려면 무조건 리프 노드까지 도달해야 합니다.

📌 5-4. 한 줄 정리

  • 두 인덱스의 핵심 차이는 리프 노드가 '실제 데이터'를 담고 있느냐(클러스터형), 아니면 다시 찾아갈 'PK 주소'가 담긴 인덱스 테이블이냐(비클러스터형)의 차이입니다.

💻 참고

실무에서 비클러스터형 인덱스를 설계할 때, '커버링 인덱스(Covering Index)'라는 개념을 자주 활용합니다.

인덱스에 포함된 컬럼만으로 조회가 끝나서 실제 테이블을 다시 참조하지 않아도 되는 경우인데, 위에서 배운 2단계 탐색 과정을 1단계로 줄여주는 아주 중요한 성능 최적화 기법입니다.

💡 비유로 이해하기

클러스터형 인덱스사전과 같습니다.
단어(ID)를 찾으면 그 자리에 바로 뜻(데이터)이 적혀 있습니다.

비클러스터형 인덱스전공 서적 맨 뒤의 색인(Index)과 같습니다.
키워드(name)를 찾으면 '몇 페이지(PK)'로 가라고 적혀 있고, 우리는 그 페이지를 다시 펼쳐야 실제 내용(데이터)을 볼 수 있습니다.


📂 6. 인덱스의 종류와 생성 방법

인덱스는 목적에 따라 클러스터형, 비클러스터형, 고유 인덱스로 구분하여 생성하며 각각 데이터 저장 방식이 다릅니다.

📌 6-1. 클러스터형 인덱스 (Clustered Index) 생성

테이블의 실제 데이터 저장 순서를 결정하는 가장 강력한 인덱스입니다.

  • 생성 방법

    • 별도의 구문 없이 테이블 생성 시 Primary Key(기본 키)를 설정하면 자동으로 생성됩니다.
  • 특징

    • 테이블마다 단 하나만 존재할 수 있습니다.
    • 인덱스를 따라가면 추가 탐색 없이 바로 데이터에 접근할 수 있어 매우 빠릅니다.
  • 코드 예시

    CREATE TABLE users (
        id INT PRIMARY KEY,
        name VARCHAR(50)
    ); [cite: 1088-1091]

📌 6-2. 기본 인덱스 (비클러스터형 인덱스) 생성

하나 또는 여러 컬럼에 대해 명시적으로 인덱스를 추가하는 가장 보편적인 방법입니다.

  • 생성 방법

    • CREATE INDEX 구문을 사용하여 생성합니다.
  • 특징

    • 이미 PK로 인한 클러스터형 인덱스가 존재하기 때문에, 이 방식으로 만든 인덱스는 비클러스터형으로 생성됩니다.
  • 코드 예시

    CREATE INDEX idx_users_name ON users (name);

📌 6-3. 고유 인덱스 (Unique Index) 생성

중복되지 않는 값을 보장해야 하는 컬럼(이메일, 주민번호 등)에 사용합니다.

  • 생성 방법

    • CREATE UNIQUE INDEX 구문을 사용하거나 컬럼에 UNIQUE 제약 조건을 추가합니다.
  • 특징

    • 중복 방지라는 제약 조건이 주요 목적이지만, 내부적으로는 인덱스가 생성되어 검색 속도도 향상됩니다.

    • 보통은 비클러스터형으로 생성되지만, 만약 Primary Key로 지정된다면 클러스터형으로 생성됩니다.

  • 코드 예시

    CREATE UNIQUE INDEX idx_users_email ON users (email);

📌 6-4. 헷갈리기 쉬운 포인트 / 오해 정리

  • 인덱스를 만들면 무조건 조회가 빨라지나요?

    • 작은 테이블에서는 오히려 전체를 훑는 것이 빠를 수 있고, 데이터 변경(INSERT, UPDATE, DELETE)이 잦은 컬럼에 인덱스를 남발하면 인덱스 유지 비용 때문에 전체적인 성능이 떨어질 수 있습니다.
  • UNIQUE 인덱스는 검색용이 아닌가요?

    • 아닙니다. 중복 체크를 하기 위해 내부적으로 데이터를 정렬된 상태로 관리하므로, 결과적으로 WHERE 절에서 해당 컬럼을 검색할 때 매우 빠른 속도를 냅니다.

📌 6-5. 한 줄 정리

  • Primary Key는 클러스터형 인덱스를, CREATE INDEX는 비클러스터형 인덱스를 생성하며, 데이터의 중복을 막으면서 검색 속도를 높이고 싶을 때는 고유 인덱스를 활용합니다.

📂 7. 복합 인덱스 (Composite Index)

📌 7-1. 여러 컬럼을 하나의 트리로, 복합 인덱스의 정의

복합 인덱스는 두 개 이상의 컬럼을 하나의 인덱스로 묶어서 생성하는 자료구조입니다.

실무에서는 하나의 컬럼만으로 검색하기보다 WHERE name = '이수진' AND age = 30처럼 여러 조건을 동시에 만족하는 데이터를 찾을 때가 많습니다.

이때 복합 인덱스를 사용하면 데이터베이스가 여러 컬럼을 하나의 트리 구조 내에서 관리하므로 검색 효율을 비약적으로 높일 수 있습니다.

📌 7-2. 컬럼 순서가 성능의 '전부'인 이유

복합 인덱스를 설계할 때 가장 주의할 점은 컬럼의 배치 순서입니다.

  1. 왼쪽 컬럼 우선 정렬

    • (name, age)로 인덱스를 구성하면, 데이터는 우선 name을 기준으로 정렬되고, 그 안에서 같은 이름을 가진 데이터들끼리만 다시 age 순으로 정렬됩니다.
  2. 인덱스 테이블의 민낯

    • 인덱스 테이블을 보면 name은 깔끔하게 정렬되어 있지만, age 컬럼만 떼어놓고 보면 값이 뒤죽박죽 섞여 있는 것을 볼 수 있습니다.
  3. 사용 규칙

    • 따라서 인덱스를 제대로 타려면 인덱스를 생성할 때 지정한 첫 번째 컬럼부터 순서대로 WHERE 절에 포함되어야 합니다.

    • 인덱스 활용 가능

      • nameage를 모두 조회하거나, 왼쪽 컬럼인 name만 단독으로 조회할 때
    • 인덱스 활용 불가

      • 첫 번째 컬럼인 name 없이 age 조건만 사용하는 경우

📌 7-3. 데이터베이스의 두뇌, 실행 계획 (Execution Plan)

우리가 쿼리를 날리면 데이터베이스는 즉시 실행하는 것이 아니라 최적의 실행 계획을 세웁니다.

  • 실행 계획 수립

    • 쿼리의 조건문과 테이블에 생성된 인덱스 현황을 모두 확인하여 가장 빠른 길을 찾습니다.
  • Optimizer의 판단

    • 만약 WHERE 절에 age 조건만 있다면, DB는 "(name, age) 복합 인덱스를 타봤자 어차피 age가 정렬되어 있지 않아 이득이 없다"고 판단합니다.
  • Full Scan 결정

    • 이 경우 인덱스를 건너뛰고 테이블 전체를 하나씩 다 훑는 풀 스캔(Full Scan)을 선택하게 됩니다.

    • 즉, 인덱스를 만들어 뒀어도 순서가 맞지 않으면 무용지물이 되는 것입니다.

📌 7-4. 헷갈리기 쉬운 포인트 / 오해 정리

  • 컬럼 3개를 묶으면 3개 다 써야 인덱스가 타나요?

    • 아닙니다. (col1, col2, col3) 인덱스라면 col1만 쓰거나 col1, col2만 써도 인덱스를 탈 수 있습니다.

    • 오직 순서를 건너뛰거나 첫 번째 컬럼을 빼먹었을 때만 문제가 됩니다.

  • 인덱스가 있으면 무조건 빨라진다?

    • DB의 실행 계획에 따라 인덱스보다 풀 스캔이 빠르다고 판단되면 인덱스를 무시할 수도 있습니다.

📌 7-5. 한 줄 정리

  • 복합 인덱스는 왼쪽 컬럼부터 정렬되는 특성이 있으므로, 반드시 첫 번째 컬럼이 조건절에 포함되어야 DB의 실행 계획이 인덱스를 타는 방향으로 수립됩니다.

💻 참고

프론트엔드에서도 다중 필터 기능을 구현할 때 백엔드의 복합 인덱스 설계를 알아야 합니다.

예를 들어 '카테고리'와 '태그'로 검색하는데 인덱스가 (카테고리, 태그) 순이라면, 사용자가 태그만 선택했을 때 검색 속도가 급격히 느려질 수 있다는 점을 인지하고 기획이나 API 설계를 조율할 줄 알아야 합니다.


📂 8. 인덱스와 성능

인덱스는 조회 성능(SELECT)을 비약적으로 향상시키지만, 데이터 변경(DML) 작업 시에는 유지 비용으로 인해 성능을 저하시키는 트레이드오프가 존재합니다.

📌 8-1. 조회의 효율성: 수십만 데이터 속에서 단숨에 찾기

도서관 분류표가 있으면 수만 권의 책 사이에서 원하는 책을 바로 찾듯, 인덱스가 있으면 대량의 데이터 검색이 매우 빨라집니다.

  • 검색 최적화

    • 예를 들어 수십만 명의 직원 중에서 부서명이 '개발팀'인 사람을 조회할 때, 인덱스가 없다면 모든 데이터를 다 훑는 풀 스캔(Full Scan)을 해야 합니다.

    • 하지만 인덱스가 있다면 딱 해당 위치만 조회하면 되므로 속도가 압도적입니다.

  • 연산 최적화

    • JOIN을 통해 테이블 여러 개를 비교하거나, 데이터를 순서대로 재배치하는 ORDER BY, GROUP BY 연산 시에도 미리 정렬된 인덱스 상태를 활용할 수 있어 쿼리 실행 시간을 크게 줄일 수 있습니다.

📌 8-2. 쓰기의 비용: 인덱스도 결국 데이터다

많은 개발자들이 간과하는 부분이 바로 이 지점입니다.
인덱스는 공짜가 아닙니다.

  • 유지 비용 발생

    • INSERT, UPDATE, DELETE 등 데이터가 변경될 때마다 데이터베이스는 인덱스 테이블도 함께 업데이트하고 정렬 상태를 유지해야 합니다.
  • 속도 저하

    • 특히 자주 바뀌는 컬럼에 인덱스를 걸어두면 수정할 때마다 인덱스 구조를 다시 짜야 하므로 삽입 및 갱신 속도가 눈에 띄게 느려질 수 있습니다.

📌 8-3. 헷갈리기 쉬운 포인트 / 오해 정리

  • 수정(UPDATE) 시에만 느려진다?
    • 아닙니다. 삭제(DELETE) 시에도 인덱스 테이블에서 해당 데이터를 '사용 안 함'으로 표시하거나 구조를 정리해야 하므로 성능에 영향을 줍니다.

📌 8-4. 한 줄 정리

  • 인덱스는 SELECT 성능을 극대화하기 위한 도구이지만, 데이터 변경(DML) 작업 시 발생하는 유지 비용과의 트레이드 오프를 고려하여 설계해야 합니다.

💻 참고

실무에서는 단순히 WHERE 조건뿐만 아니라 ORDER BYGROUP BY가 자주 일어나는 컬럼에도 인덱스를 전략적으로 배치합니다.

하지만 가장 중요한 건 주기적으로 사용되지 않는 인덱스를 제거하는 것입니다.

사용되지 않는 인덱스는 시스템의 쓰기 성능만 갉아먹는 '부채'와 같기 때문입니다.


📂 9. 데이터 최적화

📌 9-1. 샤딩(Sharding): 물리적 서버 분산

하나의 큰 테이블에 모든 데이터를 담다 보면, 아무리 인덱스가 좋아도 서버 한 대가 감당해야 할 부하가 너무 커집니다.

이때 샤딩을 사용합니다.

  • 동작 방식

    • 데이터를 수평으로 잘라 각 조각(Shard)을 서로 다른 DB 서버에 분산시킵니다.

    • 예를 들어, 사용자 ID 구간별로 별도의 샤드를 구성하는 방식입니다.

  • 장점

    • 하나의 DB 서버에 과부하가 걸리지 않습니다.
    • 각 서버는 자신에게 배정된 구간만 처리하면 되기 때문에 전체 시스템의 성능과 확장성이 비약적으로 좋아집니다.
  • 핵심

    • 샤딩은 '물리적인 분산'입니다.
    • 아예 컴퓨터(서버) 자체가 여러 대가 되는 것입니다.

📌 9-2. 파티셔닝(Partitioning): 논리적 테이블 분할

샤딩이 서버를 나누는 것이라면, 파티셔닝은 집(DB)은 그대로 두고 방(Table)만 나누는 것입니다.

  • 동작 방식

    • 논리적으로는 사용자에게 하나의 테이블처럼 보이지만, DB 내부적으로는 파티션 1, 파티션 2와 같이 물리적으로 분리된 구조로 저장합니다.
  • 사용자 입장

    • 쿼리를 날릴 때는 하나의 테이블에 날리는 것과 같지만, 실제 DB는 해당 데이터가 있는 파티션에서만 데이터를 찾습니다.
  • 핵심

    • 파티셔닝은 하나의 DB 내에서의 '논리적인 분산'에 가깝습니다.

    • 물론 파일 시스템 수준에서는 분리되지만, 샤딩처럼 서버 장비 자체가 나뉘는 것은 아닙니다.

📌 9-3. 헷갈리기 쉬운 포인트 / 오해 정리

  • 샤딩과 파티셔닝의 가장 큰 차이는 무엇인가요?

    • 구분 기준

      • 이 둘을 구분하는 가장 정확한 기준은 '물리적인 서버 분산'인가, '논리적인 테이블 분할'인가 입니다.
    • 근본적인 차이

      • 샤딩은 데이터베이스 자체가 여러 개로 쪼개져 다른 서버에 물리적으로 나뉘는 물리적 분산이고, 파티셔닝은 동일한 데이터베이스 내에서 테이블을 쪼개어 관리하는 논리적 분산이라는 점에 근본적인 차이가 있습니다.

📌 9-4. 한 줄 정리

  • 샤딩은 물리적인 여러 서버로 데이터를 쪼개어 분산하는 것이고, 파티셔닝은 하나의 DB 서버 내에서 큰 테이블을 논리적으로 쪼개어 관리하는 최적화 기법입니다.

🎁 10. 정리

🔑 요약

  • 인덱스의 두 얼굴 (Clustered vs Non-Clustered)

    • 데이터 자체가 정렬된 사전(Clustered)과, 별도의 페이지 번호를 찾아가는 색인(Non-Clustered)의 차이를 명확히 해야 합니다.

    • 특히 비클러스터형은 최종적으로 PK를 타고 실제 데이터로 가야 한다는 점(2단계 탐색)이 포인트입니다.

  • 왜 B+Tree인가?

    • 모든 노드에 데이터를 두는 B-Tree와는 달리, 데이터는 리프 노드에만 몰아넣고 연결 리스트로 이은 B+Tree가 현대 DB의 표준입니다.
    • 이는 대량의 데이터를 훑는 범위 검색에서 압도적인 효율을 보여줍니다.
  • 복합 인덱스의 황금률, '왼쪽부터'

    • 복합 인덱스에서 컬럼 순서는 성능의 전부입니다.
    • 첫 번째 컬럼을 조건절에서 빼먹는 순간, 공들여 만든 인덱스는 무용지물이 되고 DB는 '풀 스캔'이라는 고된 길을 선택하게 됩니다.
  • 확장 전략: 샤딩 vs 파티셔닝

    • 서버 자체를 여러 대로 쪼개는 물리적 분산인 샤딩, 하나의 서버 내에서 방(테이블)만 나누는 논리적 분할인 파티셔닝을 구분해야 합니다.
    • 대규모 트래픽 환경에서는 이 두 전략의 적절한 조합이 필수적입니다.

0개의 댓글