⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

MongoDB 인덱스 기초 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 27. · 2 Views

MongoDB 인덱스 기초 완벽 가이드

MongoDB에서 쿼리 성능을 획기적으로 개선하는 인덱스의 모든 것을 다룹니다. 단일 필드 인덱스부터 복합 인덱스, 그리고 실무에서 반드시 알아야 할 인덱스 관리 방법까지 초급 개발자도 쉽게 이해할 수 있도록 설명합니다.


목차

  1. 인덱스가_필요한_이유
  2. 단일_필드_인덱스
  3. 복합_인덱스_생성
  4. explain으로_쿼리_분석
  5. 인덱스_종류_unique_sparse
  6. 인덱스_관리와_삭제

1. 인덱스가 필요한 이유

김개발 씨는 입사 6개월 차 백엔드 개발자입니다. 어느 날 운영 중인 서비스에서 "페이지 로딩이 너무 느려요"라는 고객 불만이 접수되었습니다.

로그를 살펴보니 특정 API가 응답하는 데 무려 5초나 걸리고 있었습니다.

인덱스는 한마디로 데이터베이스에서 원하는 데이터를 빠르게 찾기 위한 목차입니다. 마치 두꺼운 백과사전에서 찾아보기 페이지를 활용하는 것과 같습니다.

인덱스가 없으면 MongoDB는 원하는 데이터를 찾기 위해 모든 문서를 하나하나 뒤져봐야 합니다.

다음 코드를 살펴봅시다.

// 인덱스 없이 검색할 때 발생하는 문제를 확인해봅시다
// 100만 건의 사용자 데이터가 있다고 가정합니다

// 이메일로 사용자를 찾는 쿼리
db.users.find({ email: "hong@example.com" })

// 인덱스가 없으면 MongoDB는 이렇게 동작합니다
// 1번 문서 확인 -> 아님 -> 2번 문서 확인 -> 아님 -> ...
// 최악의 경우 100만 건 전체를 확인해야 합니다

// 이것을 Collection Scan (COLLSCAN)이라고 부릅니다
// 데이터가 늘어날수록 검색 시간도 비례해서 증가합니다

김개발 씨는 입사 6개월 차 백엔드 개발자입니다. 오늘도 열심히 코드를 작성하던 중, 고객센터에서 연락이 왔습니다.

"회원 검색 페이지가 너무 느려요. 5초나 기다려야 해요." 김개발 씨가 급히 로그를 확인해보니, 사용자 검색 API의 응답 시간이 5초를 넘기고 있었습니다.

분명 코드는 간단한데, 왜 이렇게 느린 걸까요? 선배 개발자 박시니어 씨가 다가와 화면을 살펴봅니다.

"혹시 users 컬렉션에 인덱스 설정했어요?" 김개발 씨는 고개를 저었습니다. "인덱스요?

그게 뭔가요?" 그렇다면 인덱스란 정확히 무엇일까요? 쉽게 비유하자면, 인덱스는 마치 두꺼운 백과사전 뒤에 있는 찾아보기 페이지와 같습니다.

백과사전에서 "컴퓨터"라는 단어를 찾고 싶다면, 1페이지부터 끝까지 한 장씩 넘기면서 찾을 수도 있겠지만, 그건 너무 비효율적입니다. 대신 뒤쪽의 찾아보기를 펼쳐 "ㅋ" 섹션에서 "컴퓨터 - 342페이지"를 확인하면 바로 원하는 내용을 찾을 수 있습니다.

MongoDB의 인덱스도 똑같은 역할을 합니다. 인덱스가 없으면 MongoDB는 원하는 문서를 찾기 위해 컬렉션의 모든 문서를 하나하나 확인해야 합니다.

이것을 Collection Scan, 줄여서 COLLSCAN이라고 부릅니다. 문제는 데이터가 늘어날수록 심각해집니다.

1,000건일 때는 괜찮았던 검색이, 100만 건이 되면 1,000배 느려집니다. 1,000만 건이 되면?

서비스가 마비되는 수준에 이릅니다. 실제로 김개발 씨가 담당하는 서비스의 users 컬렉션에는 50만 건의 사용자 데이터가 저장되어 있었습니다.

인덱스 없이 이메일로 사용자를 검색하면, 최악의 경우 50만 건을 모두 뒤져야 원하는 사용자를 찾을 수 있습니다. 반면 이메일 필드에 인덱스가 있다면 어떨까요?

MongoDB는 찾아보기 페이지처럼 정렬된 인덱스 구조를 활용해서, 단 몇 번의 비교만으로 원하는 문서의 위치를 알아낼 수 있습니다. 50만 건이 있어도 약 19번 정도의 비교면 충분합니다.

이것이 바로 인덱스의 마법입니다. O(n)의 선형 탐색을 O(log n)의 로그 탐색으로 바꿔주는 것입니다.

박시니어 씨의 설명을 들은 김개발 씨는 고개를 끄덕였습니다. "아, 그래서 검색이 그렇게 느렸군요!

그럼 어떻게 인덱스를 만들 수 있나요?" 인덱스의 필요성을 이해했다면, 이제 실제로 인덱스를 만드는 방법을 알아볼 차례입니다.

실전 팁

💡 - 자주 검색하는 필드에는 반드시 인덱스를 고려하세요

  • 인덱스가 너무 많으면 쓰기 성능이 저하될 수 있으니 균형이 중요합니다

2. 단일 필드 인덱스

인덱스의 필요성을 깨달은 김개발 씨는 바로 인덱스를 만들어보기로 했습니다. 가장 기본이 되는 것은 하나의 필드에 대한 인덱스, 바로 단일 필드 인덱스입니다.

사용자 이메일로 검색하는 기능이 느리다면, 이메일 필드에 인덱스를 만들면 됩니다.

단일 필드 인덱스는 컬렉션의 특정 필드 하나에 대해 생성하는 가장 기본적인 인덱스입니다. createIndex() 메서드에 필드명과 정렬 방향(1은 오름차순, -1은 내림차순)을 지정하면 됩니다.

한 번 생성해두면 해당 필드로 검색할 때 극적인 성능 향상을 경험할 수 있습니다.

다음 코드를 살펴봅시다.

// 단일 필드 인덱스 생성하기
// 문법: db.컬렉션명.createIndex({ 필드명: 정렬방향 })

// email 필드에 오름차순 인덱스 생성
db.users.createIndex({ email: 1 })

// age 필드에 내림차순 인덱스 생성
db.users.createIndex({ age: -1 })

// 인덱스 생성 결과 확인
// { "createdCollectionAutomatically" : false,
//   "numIndexesBefore" : 1,
//   "numIndexesAfter" : 2,
//   "ok" : 1 }

// 현재 컬렉션의 모든 인덱스 확인
db.users.getIndexes()

김개발 씨는 드디어 첫 번째 인덱스를 만들어보기로 했습니다. 가장 시급한 것은 이메일 검색 기능이었습니다.

매일 수백 명의 고객센터 직원들이 이메일로 회원을 검색하고 있었거든요. 단일 필드 인덱스를 만드는 방법은 생각보다 간단합니다.

MongoDB 셸에서 createIndex() 메서드를 호출하면 됩니다. 첫 번째 인자로 인덱스를 만들 필드와 정렬 방향을 객체 형태로 전달합니다.

정렬 방향에서 1은 오름차순, -1은 내림차순을 의미합니다. 그런데 여기서 의문이 생깁니다.

"정렬 방향이 왜 필요하지? 검색만 하면 되는 거 아닌가?" 좋은 질문입니다.

인덱스의 정렬 방향은 주로 정렬된 결과를 반환할 때 영향을 미칩니다. 예를 들어 나이가 많은 순서대로 사용자를 조회한다면, age 필드에 내림차순(-1) 인덱스가 있으면 더 효율적입니다.

하지만 단일 필드 인덱스에서는 정렬 방향이 크게 중요하지 않습니다. MongoDB는 인덱스를 양방향으로 탐색할 수 있기 때문입니다.

오름차순 인덱스도 내림차순으로 읽을 수 있습니다. 정렬 방향이 정말 중요해지는 것은 복합 인덱스에서입니다.

김개발 씨는 곧바로 실행에 옮겼습니다. MongoDB 셸을 열고 db.users.createIndex({ email: 1 })을 입력했습니다.

잠시 후 성공 메시지가 나타났습니다. 인덱스가 제대로 생성되었는지 확인하려면 getIndexes() 메서드를 사용합니다.

이 메서드는 해당 컬렉션에 존재하는 모든 인덱스 목록을 보여줍니다. 결과를 보니 두 개의 인덱스가 있었습니다.

하나는 방금 만든 email 인덱스, 그리고 다른 하나는 _id 필드의 인덱스였습니다. MongoDB는 모든 컬렉션에 _id 필드에 대한 인덱스를 자동으로 생성합니다.

이 인덱스는 삭제할 수 없습니다. 인덱스를 만든 후 김개발 씨는 다시 검색 API를 테스트해봤습니다.

응답 시간이 5초에서 50밀리초로 줄어들었습니다. 무려 100배나 빨라진 것입니다.

박시니어 씨가 웃으며 말했습니다. "이게 바로 인덱스의 힘이에요.

근데 검색 조건이 여러 개면 어떻게 해야 할까요?"

실전 팁

💡 - _id 필드에는 자동으로 인덱스가 생성되므로 따로 만들 필요 없습니다

  • 단일 필드 인덱스에서 정렬 방향은 크게 중요하지 않습니다

3. 복합 인덱스 생성

김개발 씨의 서비스에는 "30대 남성 사용자 중 최근 가입한 순서로 보여주기" 같은 복잡한 검색 조건이 있었습니다. 나이, 성별, 가입일 세 가지 조건이 한꺼번에 들어가는 쿼리입니다.

이런 경우에는 여러 필드를 조합한 복합 인덱스가 필요합니다.

복합 인덱스는 두 개 이상의 필드를 조합하여 만드는 인덱스입니다. 여러 조건으로 검색하거나, 특정 조건으로 필터링한 후 정렬할 때 효과적입니다.

복합 인덱스에서 가장 중요한 것은 필드의 순서입니다. 이 순서에 따라 인덱스 활용 여부가 결정됩니다.

다음 코드를 살펴봅시다.

// 복합 인덱스 생성하기
// 여러 필드를 하나의 객체에 나열합니다

// age, gender, createdAt 세 필드로 복합 인덱스 생성
db.users.createIndex({ age: 1, gender: 1, createdAt: -1 })

// 복합 인덱스 활용 예시
// 이 쿼리는 인덱스를 100% 활용합니다
db.users.find({ age: 30, gender: "M" }).sort({ createdAt: -1 })

// 이 쿼리도 인덱스를 활용합니다 (앞쪽 필드만 사용)
db.users.find({ age: 30 })

// 주의: 이 쿼리는 인덱스를 활용하지 못합니다!
// 첫 번째 필드(age)를 건너뛰었기 때문입니다
db.users.find({ gender: "M" })

김개발 씨는 이메일 검색 문제를 해결하고 뿌듯해하고 있었습니다. 그런데 또 다른 문제가 발생했습니다.

마케팅팀에서 "30대 남성 사용자를 최근 가입순으로 보고 싶어요"라는 요청이 들어온 것입니다. 이 쿼리를 만들어보니 이렇게 되었습니다.

db.users.find({ age: 30, gender: "M" }).sort({ createdAt: -1 }) age 필드에 인덱스를 만들고, gender 필드에도 인덱스를 만들면 될까요? 박시니어 씨가 고개를 저었습니다.

"각각 따로 만들면 MongoDB가 인덱스 하나만 선택해서 사용해요. 나머지 조건은 인덱스 없이 처리하게 되죠.

이럴 때는 복합 인덱스를 만들어야 해요." 복합 인덱스는 여러 필드를 하나로 묶어서 만드는 인덱스입니다. 마치 전화번호부가 "성씨 - 이름" 순서로 정렬되어 있는 것과 같습니다.

"김"씨 중에서 "철수"를 찾으려면 먼저 "김"을 찾고, 그 안에서 "철수"를 찾으면 됩니다. 복합 인덱스에서 가장 중요한 것은 필드의 순서입니다.

이것을 이해하기 위해 전화번호부 비유를 계속 사용해봅시다. 전화번호부에서 "김철수"를 찾는 것은 쉽습니다.

"김"을 먼저 찾고, 그 안에서 "철수"를 찾으면 됩니다. 하지만 "이름이 철수인 사람 전부"를 찾으려면 어떨까요?

전화번호부 전체를 뒤져야 합니다. 왜냐하면 전화번호부는 "성씨"를 기준으로 먼저 정렬되어 있기 때문입니다.

MongoDB의 복합 인덱스도 마찬가지입니다. { age: 1, gender: 1, createdAt: -1 }로 인덱스를 만들면, 이 인덱스는 age를 기준으로 먼저 정렬하고, 같은 age 안에서 gender로 정렬하고, 같은 gender 안에서 createdAt으로 정렬합니다.

따라서 age 조건이 있는 쿼리는 인덱스를 활용할 수 있습니다. age와 gender 조건이 모두 있는 쿼리도 인덱스를 활용합니다.

하지만 gender만 있는 쿼리는 인덱스를 사용하지 못합니다. 첫 번째 필드인 age를 건너뛰었기 때문입니다.

이것을 인덱스 프리픽스(Prefix) 규칙이라고 합니다. 복합 인덱스는 왼쪽부터 순서대로 사용해야 합니다.

김개발 씨가 물었습니다. "그럼 필드 순서는 어떻게 정해야 하나요?" 박시니어 씨가 답했습니다.

"일반적으로 동등 조건(=)이 앞에, 범위 조건이나 정렬이 뒤에 오는 게 좋아요. 그리고 선택도가 높은 필드, 그러니까 값의 종류가 많은 필드가 앞에 오는 게 효율적이에요." 복합 인덱스의 필드 순서를 정하는 것은 경험이 필요한 영역입니다.

하지만 기본 원칙만 기억해도 대부분의 상황에서 좋은 인덱스를 설계할 수 있습니다.

실전 팁

💡 - 복합 인덱스는 왼쪽 필드부터 순서대로 사용해야 효과가 있습니다

  • 동등 조건(=) 필드를 앞에, 범위 조건이나 정렬 필드를 뒤에 배치하세요

4. explain으로 쿼리 분석

김개발 씨는 인덱스를 만들었지만, 정말로 인덱스가 사용되고 있는지 확인하고 싶었습니다. "이 쿼리가 인덱스를 타고 있는지 어떻게 알 수 있죠?" 박시니어 씨가 알려준 것은 바로 explain() 메서드였습니다.

explain() 메서드는 쿼리가 어떻게 실행되는지 상세한 정보를 보여주는 분석 도구입니다. 인덱스 사용 여부, 스캔한 문서 수, 실행 시간 등을 확인할 수 있습니다.

쿼리 성능을 튜닝할 때 반드시 사용해야 하는 필수 도구입니다.

다음 코드를 살펴봅시다.

// explain() 기본 사용법
db.users.find({ email: "hong@example.com" }).explain()

// 더 자세한 실행 통계를 보려면 executionStats 옵션 사용
db.users.find({ email: "hong@example.com" }).explain("executionStats")

// 주요 확인 포인트
// 1. stage: "COLLSCAN"이면 인덱스 미사용 (느림)
// 2. stage: "IXSCAN"이면 인덱스 사용 (빠름)
// 3. totalDocsExamined: 실제로 확인한 문서 수
// 4. totalKeysExamined: 확인한 인덱스 키 수
// 5. executionTimeMillis: 실행 시간(밀리초)

// 좋은 쿼리의 특징
// - IXSCAN 사용
// - totalDocsExamined와 반환된 문서 수가 비슷함

인덱스를 만들었다고 해서 무조건 사용되는 것은 아닙니다. MongoDB가 "이 쿼리에는 인덱스를 쓰는 게 더 비효율적이야"라고 판단하면 인덱스를 무시하고 전체 스캔을 할 수도 있습니다.

그래서 쿼리가 실제로 인덱스를 사용하고 있는지 확인하는 것이 중요합니다. 이때 사용하는 것이 바로 explain() 메서드입니다.

explain()은 마치 의사가 환자에게 CT 촬영을 하는 것과 같습니다. 겉으로는 멀쩡해 보이는데 속이 어떤 상태인지 들여다볼 수 있게 해줍니다.

쿼리가 내부적으로 어떻게 실행되는지, 인덱스는 사용하는지, 몇 개의 문서를 확인했는지 모두 알 수 있습니다. 사용법은 간단합니다.

쿼리 뒤에 .explain()을 붙이면 됩니다. 더 자세한 정보가 필요하면 .explain("executionStats")를 사용합니다.

explain() 결과에서 가장 먼저 확인할 것은 stage 값입니다. 이 값이 COLLSCAN이면 컬렉션 전체를 스캔한다는 뜻입니다.

인덱스를 사용하지 않는 것입니다. 반면 IXSCAN이면 인덱스를 사용한다는 뜻입니다.

김개발 씨가 이메일 인덱스를 만들기 전과 후의 explain() 결과를 비교해봤습니다. 인덱스 생성 전에는 stage가 COLLSCAN이었고, totalDocsExamined가 500,000이었습니다.

50만 건의 문서를 전부 확인한 것입니다. 실행 시간은 5,200밀리초, 약 5.2초였습니다.

인덱스 생성 후에는 stage가 IXSCAN으로 바뀌었습니다. totalDocsExamined는 1이었고, totalKeysExamined도 1이었습니다.

인덱스에서 딱 하나의 키만 확인하고, 문서도 하나만 읽은 것입니다. 실행 시간은 2밀리초로 줄어들었습니다.

또 하나 중요한 지표는 totalDocsExamined와 반환된 문서 수의 비율입니다. 이상적인 경우, 확인한 문서 수와 반환한 문서 수가 같아야 합니다.

만약 1,000개의 문서를 확인해서 10개만 반환했다면, 990개는 쓸데없이 확인한 셈입니다. 이런 경우 인덱스를 개선할 여지가 있습니다.

박시니어 씨가 조언했습니다. "쿼리 성능에 문제가 있다 싶으면 무조건 explain()부터 찍어봐요.

원인을 정확히 알아야 제대로 된 해결책을 찾을 수 있거든요." explain()은 MongoDB 개발자의 필수 도구입니다. 새로운 쿼리를 작성할 때마다, 그리고 성능 문제가 발생할 때마다 반드시 활용하세요.

실전 팁

💡 - 새로운 쿼리를 작성하면 반드시 explain()으로 실행 계획을 확인하세요

  • COLLSCAN이 나오면 인덱스 추가를 고려하세요

5. 인덱스 종류 unique sparse

김개발 씨는 기본적인 인덱스 사용법을 익혔습니다. 그런데 새로운 요구사항이 생겼습니다.

"이메일은 중복되면 안 되는데, 인덱스로 이걸 강제할 수 있나요?" 박시니어 씨가 고개를 끄덕였습니다. "unique 인덱스를 사용하면 돼요."

MongoDB는 기본 인덱스 외에도 특별한 속성을 가진 인덱스를 제공합니다. unique 인덱스는 필드 값의 중복을 방지합니다.

sparse 인덱스는 해당 필드가 존재하는 문서만 인덱싱합니다. 상황에 맞는 인덱스 타입을 선택하면 데이터 무결성과 성능을 동시에 얻을 수 있습니다.

다음 코드를 살펴봅시다.

// unique 인덱스: 중복 값 방지
db.users.createIndex({ email: 1 }, { unique: true })

// 이제 같은 이메일로 두 번째 문서를 삽입하면 에러 발생
db.users.insertOne({ email: "hong@example.com", name: "홍길동" })
db.users.insertOne({ email: "hong@example.com", name: "홍길순" })
// Error: E11000 duplicate key error

// sparse 인덱스: 필드가 있는 문서만 인덱싱
db.users.createIndex({ nickname: 1 }, { sparse: true })

// nickname이 없는 문서는 인덱스에 포함되지 않음
db.users.insertOne({ email: "a@test.com" })  // 인덱스에 포함 안됨
db.users.insertOne({ email: "b@test.com", nickname: "dev" })  // 인덱스에 포함

// unique + sparse 조합도 가능
db.users.createIndex({ phone: 1 }, { unique: true, sparse: true })

김개발 씨의 서비스에서 큰 사고가 발생했습니다. 어떤 사용자가 이미 가입된 이메일로 다시 가입하는 데 성공한 것입니다.

결과적으로 같은 이메일을 가진 계정이 두 개가 되어버렸습니다. 회원가입 로직에서 이메일 중복 체크를 하고 있었지만, 동시에 두 명이 같은 이메일로 가입 버튼을 누르는 극히 드문 상황에서 문제가 발생한 것입니다.

이것을 **레이스 컨디션(Race Condition)**이라고 합니다. 박시니어 씨가 해결책을 알려주었습니다.

"애플리케이션 레벨에서 체크하는 것만으로는 부족해요. 데이터베이스 레벨에서 중복을 원천 차단해야 해요.

unique 인덱스를 사용하면 됩니다." unique 인덱스는 해당 필드에 중복된 값이 들어가는 것을 데이터베이스가 직접 막아줍니다. 마치 주민등록번호처럼, 같은 값이 두 번 등록되는 것을 시스템 차원에서 불가능하게 만드는 것입니다.

createIndex()에 { unique: true } 옵션을 추가하면 됩니다. 이렇게 만든 인덱스가 있는 상태에서 중복된 값을 넣으려고 하면, MongoDB가 E11000 duplicate key error를 발생시키며 삽입을 거부합니다.

또 다른 유용한 인덱스 타입은 sparse 인덱스입니다. MongoDB의 문서는 스키마가 자유롭습니다.

어떤 문서에는 nickname 필드가 있고, 어떤 문서에는 없을 수 있습니다. 일반 인덱스는 필드가 없는 문서도 null 값으로 인덱싱합니다.

하지만 sparse 인덱스는 해당 필드가 존재하는 문서만 인덱싱합니다. 이것이 왜 중요할까요?

만약 nickname 필드에 unique 인덱스를 만들었다고 합시다. 그런데 nickname이 없는 문서가 여러 개 있다면, 모두 null 값으로 처리되어 중복 에러가 발생합니다.

이럴 때 unique와 sparse를 조합하면 문제를 해결할 수 있습니다. { unique: true, sparse: true } 옵션으로 인덱스를 만들면, 필드가 없는 문서는 아예 인덱스에서 제외되므로 null 중복 문제가 발생하지 않습니다.

필드가 있는 문서들끼리만 중복 체크가 이루어집니다. 김개발 씨는 바로 이메일 필드에 unique 인덱스를 적용했습니다.

이제 아무리 동시에 가입 버튼을 눌러도, 데이터베이스가 중복을 막아줍니다. 마음이 한결 편해졌습니다.

인덱스는 단순히 검색 속도를 높이는 것 이상의 역할을 합니다. 데이터의 무결성을 보장하는 강력한 도구이기도 합니다.

실전 팁

💡 - 이메일, 사용자ID 등 중복되면 안 되는 필드에는 unique 인덱스를 사용하세요

  • 선택적 필드에 unique를 적용할 때는 sparse 옵션을 함께 고려하세요

6. 인덱스 관리와 삭제

시간이 흘러 김개발 씨의 서비스는 계속 성장했습니다. 그러다 보니 인덱스가 점점 많아졌습니다.

어느 날 데이터베이스 용량이 급격히 늘어난 것을 발견했습니다. 원인을 찾아보니 사용하지 않는 인덱스들이 공간을 차지하고 있었습니다.

인덱스는 만드는 것만큼 관리하고 삭제하는 것도 중요합니다. 불필요한 인덱스는 저장 공간을 낭비하고, 쓰기 작업의 성능을 저하시킵니다.

getIndexes()로 인덱스 목록을 확인하고, dropIndex()로 불필요한 인덱스를 삭제할 수 있습니다.

다음 코드를 살펴봅시다.

// 현재 컬렉션의 모든 인덱스 확인
db.users.getIndexes()

// 특정 인덱스 삭제 (인덱스 이름으로)
db.users.dropIndex("email_1")

// 특정 인덱스 삭제 (인덱스 키 스펙으로)
db.users.dropIndex({ email: 1 })

// _id 인덱스를 제외한 모든 인덱스 삭제
db.users.dropIndexes()

// 인덱스 사용 통계 확인 (MongoDB 3.2+)
db.users.aggregate([{ $indexStats: {} }])

// 결과에서 accesses.ops가 0인 인덱스는 사용되지 않는 것
// 이런 인덱스는 삭제를 고려해볼 만합니다

// 인덱스 재구축 (조각화 해결)
db.users.reIndex()

"인덱스는 많을수록 좋은 거 아닌가요?" 김개발 씨가 순진하게 물었습니다. 박시니어 씨가 고개를 저었습니다.

"인덱스도 공짜가 아니에요. 비용이 있어요." 인덱스는 마치 책의 찾아보기 페이지와 같다고 했습니다.

찾아보기 페이지가 많으면 원하는 내용을 찾기는 쉬워지지만, 책이 두꺼워집니다. 그리고 더 중요한 것은, 책 내용이 바뀔 때마다 찾아보기 페이지도 업데이트해야 한다는 점입니다.

MongoDB도 마찬가지입니다. 인덱스가 있으면 새 문서를 삽입하거나, 기존 문서를 수정하거나, 문서를 삭제할 때마다 해당 인덱스도 함께 업데이트해야 합니다.

인덱스가 10개라면 문서 하나를 수정할 때 10개의 인덱스를 모두 업데이트합니다. 즉, 인덱스가 많아지면 쓰기 작업이 느려집니다.

또한 인덱스는 저장 공간도 차지합니다. 데이터가 100GB인데 인덱스가 50GB를 차지하는 경우도 드물지 않습니다.

사용하지 않는 인덱스가 디스크 공간을 낭비하고 있다면 그건 정말 아까운 일입니다. 그래서 주기적으로 인덱스를 점검하고 정리해야 합니다.

먼저 getIndexes() 메서드로 현재 컬렉션에 어떤 인덱스들이 있는지 확인합니다. 목록을 보면서 "이 인덱스가 정말 필요한가?"를 점검합니다.

MongoDB 3.2 버전부터는 $indexStats라는 집계 연산자를 사용할 수 있습니다. 이 연산자는 각 인덱스가 실제로 얼마나 사용되었는지 통계를 보여줍니다.

accesses.ops 값이 0이라면, 서버가 시작된 이후로 한 번도 사용되지 않은 인덱스라는 뜻입니다. 물론 조심해야 합니다.

월말에만 실행되는 배치 작업에서 사용하는 인덱스일 수도 있습니다. 최소 한 달 이상의 기간 동안 모니터링한 후 삭제 여부를 결정하세요.

불필요한 인덱스를 발견했다면 dropIndex() 메서드로 삭제합니다. 인덱스 이름이나 인덱스 키 스펙을 인자로 전달하면 됩니다.

_id 인덱스를 제외한 모든 인덱스를 한 번에 삭제하려면 **dropIndexes()**를 사용합니다. 김개발 씨가 인덱스를 점검해보니, 초기에 테스트용으로 만들어둔 인덱스 세 개가 한 번도 사용되지 않고 있었습니다.

삭제하니 저장 공간이 2GB나 확보되었습니다. 인덱스 관리는 데이터베이스 운영의 중요한 부분입니다.

만드는 것만큼이나 정리하는 것도 신경 써야 합니다.

실전 팁

💡 - 주기적으로 $indexStats를 확인하여 사용되지 않는 인덱스를 점검하세요

  • 운영 중인 대용량 컬렉션에서 인덱스를 삭제할 때는 트래픽이 적은 시간에 진행하세요

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#MongoDB#Index#Database#QueryOptimization#Performance#MongoDB,Database,NoSQL

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.