MongoDB Performance Advisor 활용법, 중복 인덱스와 죽은 코드까지 함께 정리해야 하는 이유
MongoDB Atlas를 운영하다 보면 Performance Advisor에서 Drop Indexes, Unused Indexes, Redundant Indexes 같은 권고를 발견할 수 있습니다.
이때 권고된 인덱스를 Atlas 화면이나 MongoDB Shell에서 바로 삭제하는 것만으로 작업을 끝내기 쉽습니다. 하지만 불필요한 인덱스가 만들어진 원인을 코드에서 제거하지 않으면 다음 배포나 서버 재시작 과정에서 같은 인덱스가 다시 생성될 수 있습니다.
따라서 MongoDB Performance Advisor의 권고는 단순한 데이터베이스 정리 작업이 아니라, 사용하지 않는 API와 모델, 중복된 스키마 설정, 오래된 기능 등 이른바 ‘죽은 코드’를 점검하는 출발점으로 활용하는 것이 좋습니다.
MongoDB Performance Advisor란?
MongoDB Atlas의 Performance Advisor는 실제 데이터베이스 사용 패턴을 분석해 성능 개선 항목을 제안하는 기능입니다.
대표적인 인덱스 제거 권고는 다음과 같습니다.
Unused Indexes: 일정 기간 쿼리에 사용되지 않은 인덱스
Redundant Indexes: 다른 복합 인덱스가 동일한 역할을 대신하는 중복 인덱스
Hidden Indexes: 쿼리 실행 계획에서는 제외됐지만 계속 유지되고 있는 인덱스
불필요한 인덱스는 저장 공간만 사용하는 것이 아닙니다. 문서가 추가되거나 수정되고 삭제될 때마다 관련 인덱스도 함께 갱신되기 때문에 쓰기 성능과 운영 비용에 영향을 줄 수 있습니다.
MongoDB 공식 문서에서도 불필요하거나 중복된 인덱스를 제거하면 저장 공간을 확보하고 쓰기 성능을 개선할 수 있다고 안내합니다.
MongoDB 중복 인덱스는 왜 발생할까?
다음과 같은 인덱스가 있다고 가정해 보겠습니다.
{ area: 1 }
{ area: 1, published: 1 }{ area: 1, published: 1 } 복합 인덱스는 첫 번째 필드인 area를 기준으로 시작합니다. 따라서 다음 쿼리를 모두 지원할 수 있습니다.
db.fashionshops.find({
area: "seoul"
});db.fashionshops.find({
area: "seoul",
published: true
});특별한 옵션 차이가 없다면 { area: 1 } 단일 인덱스의 역할을 { area: 1, published: 1 } 복합 인덱스가 대신할 수 있습니다.
MongoDB Performance Advisor에서는 이런 단일 인덱스를 Redundant, 즉 중복 인덱스로 표시합니다.
다만 복합 인덱스의 필드 순서는 중요합니다. 다음 쿼리는 area 없이 published만 조회하기 때문에 위 복합 인덱스를 효율적으로 사용하지 못할 수 있습니다.
db.fashionshops.find({
published: true
});따라서 인덱스를 삭제하기 전에는 단순히 필드 이름만 비교하지 말고 실제 쿼리 조건과 정렬 순서까지 함께 확인해야 합니다.
MongoDB 권고에서 죽은 코드의 흔적을 찾을 수 있다
Performance Advisor에서 사용하지 않는 인덱스가 발견됐다고 해서 해당 기능 전체가 죽은 코드라고 단정할 수는 없습니다.
하지만 다음과 같은 문제를 발견할 수 있는 중요한 신호가 됩니다.
삭제된 화면에서 사용하던 검색 인덱스
더 이상 호출되지 않는 API Route
운영이 종료된 게시판이나 콘텐츠 유형
이전 검색 조건에 맞춰 생성했던 인덱스
모델에 중복 선언된 인덱스
리팩터링 이후 남아 있는 Repository 또는 Service
일회성 데이터 이전 스크립트
사용하지 않는 필드와 정렬 조건
배포할 때마다 실행되는 오래된 인덱스 생성 코드
예를 들어 특정 컬렉션의 category, area, author 인덱스가 장기간 사용되지 않았다면 해당 필드를 사용하는 API가 현재도 존재하는지 확인할 필요가 있습니다.
인덱스만 삭제할 것이 아니라 다음 구조를 따라가야 합니다.
MongoDB 인덱스
→ 모델 및 스키마
→ Repository 또는 데이터 접근 코드
→ API Route 및 Server Action
→ 실제 화면과 사용자 기능이 과정을 통해 데이터베이스뿐만 아니라 애플리케이션 코드 전체를 함께 정리할 수 있습니다.
MongoDB 인덱스 삭제 전 코드에서 확인할 항목
Mongoose를 사용하는 프로젝트에서는 다음과 같이 필드 단위 인덱스와 복합 인덱스가 동시에 선언될 수 있습니다.
const fashionShopSchema = new Schema({
area: {
type: String,
index: true,
},
published: {
type: Boolean,
default: false,
},
});
fashionShopSchema.index({
area: 1,
published: 1,
});이 코드는 다음 두 개의 인덱스를 만들 수 있습니다.
{ area: 1 }
{ area: 1, published: 1 }단일 인덱스가 필요하지 않다면 index: true를 제거합니다.
const fashionShopSchema = new Schema({
area: {
type: String,
},
published: {
type: Boolean,
default: false,
},
});
fashionShopSchema.index({
area: 1,
published: 1,
});프로젝트 전체에서 인덱스 관련 코드를 찾으려면 다음 명령어를 활용할 수 있습니다.
rg "index: true|schema\.index|createIndex|createIndexes|syncIndexes|ensureIndexes" .특정 필드를 검색하려면 다음과 같이 확인합니다.
rg "area|area_1|area_1_published_1" .검색 결과에서는 다음 항목을 중점적으로 점검합니다.
Mongoose Schema의
index: trueschema.index()복합 인덱스 선언MongoDB Driver의
createIndex()인덱스를 생성하는 배포 스크립트
syncIndexes()실행 코드사용하지 않는 API와 Service
해당 필드가 포함된 검색 및 정렬 쿼리
MongoDB 인덱스 사용량 확인 방법
현재 컬렉션에 생성된 인덱스는 다음 명령어로 확인할 수 있습니다.
db.fashionshops.getIndexes()각 인덱스의 사용 통계는 $indexStats를 이용해 확인할 수 있습니다.
db.fashionshops.aggregate([
{
$indexStats: {}
}
]);결과에서 accesses.ops는 해당 인덱스가 사용자 쿼리에 사용된 횟수를 나타냅니다.
{
name: "area_1",
accesses: {
ops: Long("0"),
since: ISODate("2026-07-20T10:00:00Z")
}
}다만 ops: 0이라는 결과만 보고 바로 삭제하면 안 됩니다.
인덱스 사용 통계는 서버 재시작이나 인덱스 재생성 과정에서 초기화될 수 있습니다. 또한 특정 시즌이나 관리자 작업에서만 사용하는 인덱스라면 평소에는 사용량이 나타나지 않을 수 있습니다.
따라서 다음 자료를 함께 확인하는 것이 안전합니다.
Atlas Performance Advisor 권고
$indexStats결과실제 API 호출 로그
MongoDB Query Profiler 또는 Query Insights
Repository와 Schema 코드
관리자 및 배치 작업
정기적으로만 실행되는 기능
MongoDB 인덱스는 바로 삭제하지 말고 먼저 숨겨보자
운영 중인 서비스에서 인덱스를 즉시 삭제하는 것이 부담스럽다면 먼저 해당 인덱스를 숨길 수 있습니다.
db.fashionshops.hideIndex("area_1")숨겨진 인덱스는 쿼리 플래너가 사용하지 않지만 MongoDB 내부에는 유지됩니다. 일정 기간 응답 속도와 오류, 데이터베이스 부하를 확인한 뒤 문제가 없을 때 삭제할 수 있습니다.
문제가 발견되면 다시 활성화합니다.
db.fashionshops.unhideIndex("area_1")문제가 없다면 인덱스를 삭제합니다.
db.fashionshops.dropIndex("area_1")운영 환경에서는 다음 순서를 권장합니다.
Performance Advisor 권고 확인
getIndexes()로 인덱스 옵션 확인코드에서 인덱스 생성 위치 검색
실제 쿼리와 API 사용 여부 확인
불필요한 인덱스 선언과 죽은 코드 제거
운영 인덱스를 먼저 숨김 처리
일정 기간 성능과 오류 모니터링
문제가 없으면 인덱스 삭제
재배포 후 인덱스가 다시 생성되지 않는지 확인
MongoDB 인덱스 옵션이 다르면 삭제하면 안 된다
필드 구성이 비슷해 보여도 인덱스 옵션이 다르면 서로 다른 목적을 가질 수 있습니다.
특히 다음 옵션이 적용돼 있는지 확인해야 합니다.
unique
sparse
partialFilterExpression
collation
expireAfterSeconds
hidden예를 들어 다음 두 인덱스는 같은 email 필드를 사용하지만 동일한 인덱스가 아닙니다.
db.users.createIndex(
{ email: 1 },
{ unique: true }
);db.users.createIndex(
{ email: 1, status: 1 }
);첫 번째 인덱스는 이메일 중복을 방지하는 제약 조건 역할을 합니다. 단순히 두 번째 복합 인덱스가 존재한다는 이유로 삭제하면 회원 데이터의 무결성에 문제가 생길 수 있습니다.
따라서 Performance Advisor 권고가 표시됐더라도 인덱스의 전체 설정을 확인한 뒤 삭제해야 합니다.
MongoDB 인덱스 삭제와 죽은 코드 제거를 함께 해야 하는 이유
Atlas에서 인덱스만 삭제하면 당장의 저장 공간과 쓰기 부하는 줄어들 수 있습니다. 하지만 코드에 다음 선언이 남아 있으면 인덱스가 다시 만들어질 수 있습니다.
index: trueschema.index({ area: 1 });await collection.createIndex({ area: 1 });await Model.syncIndexes();특히 운영 환경에서 autoIndex가 활성화되어 있거나 애플리케이션 시작 과정에서 인덱스 동기화를 수행한다면 재배포 이후 삭제한 인덱스가 복구될 가능성이 있습니다.
반대로 코드만 제거하고 MongoDB에 남은 인덱스를 삭제하지 않으면 기존 인덱스는 계속 저장 공간을 차지하고 쓰기 작업에도 영향을 줍니다.
결국 데이터베이스와 코드를 함께 정리해야 작업이 완성됩니다.
MongoDB Performance Advisor 점검 체크리스트
MongoDB 권고를 확인했다면 다음 체크리스트를 활용할 수 있습니다.
권고된 인덱스가 어떤 컬렉션에 있는가?
해당 인덱스의 전체 옵션은 무엇인가?
다른 복합 인덱스가 역할을 대신할 수 있는가?
실제로 어떤 쿼리에서 사용되는가?
최근 사용량이 낮은 이유가 서버 재시작 때문은 아닌가?
관리자나 배치 작업에서만 사용하는 인덱스는 아닌가?
Schema에 중복 인덱스 선언이 있는가?
배포 스크립트에서 인덱스를 다시 생성하는가?
관련 API와 화면이 현재도 사용되는가?
삭제 전 숨김 테스트를 진행했는가?
삭제 후 응답 속도와 쓰기 부하를 비교했는가?
재배포 후 인덱스가 다시 생기지 않았는가?
결론: MongoDB 권고는 코드 정리의 출발점이다
MongoDB Performance Advisor의 인덱스 제거 권고는 단순히 DROP INDEX 버튼을 누르라는 의미로만 받아들이기보다, 해당 인덱스가 왜 만들어졌고 현재 어떤 코드에서 사용되는지 추적하는 기회로 활용하는 것이 좋습니다.
중복 인덱스가 발견됐다면 Schema에 같은 인덱스가 반복 선언돼 있는지 확인해야 합니다. 사용하지 않는 인덱스가 발견됐다면 관련 API와 화면, 모델 필드가 현재도 필요한지 점검해야 합니다.
가장 안전한 방법은 다음과 같습니다.
권고 확인
→ 인덱스 사용량 분석
→ 코드와 쿼리 추적
→ 죽은 코드 및 중복 선언 제거
→ 인덱스 숨김 테스트
→ 운영 모니터링
→ 최종 삭제이 과정을 정기적으로 반복하면 MongoDB 저장 공간과 쓰기 성능을 개선할 수 있을 뿐만 아니라, 프로젝트에 쌓여 있는 오래된 코드와 불필요한 기능도 함께 줄일 수 있습니다.
MongoDB 최적화는 데이터베이스 설정만 변경하는 작업이 아닙니다. 데이터베이스에서 발견한 신호를 애플리케이션 코드까지 연결해 점검할 때 유지보수성과 운영 안정성을 함께 높일 수 있습니다.