인덱싱은 데이터베이스 성능 최적화의 핵심이며, 제대로 사용하면 쿼리 속도를 크게 향상시킬 수 있습니다.
MongoDB 인덱싱이란?
인덱싱은 데이터베이스 테이블의 검색 속도를 향상시키기 위해 사용되는 데이터 구조입니다. MongoDB에서 인덱스는 컬렉션 내 문서들의 특정 필드 값을 정렬하여 저장합니다. 이를 통해 MongoDB는 전체 컬렉션을 스캔하지 않고도 빠르게 원하는 데이터를 찾을 수 있습니다.
인덱싱의 장점
쿼리 성능 향상 : 인덱스를 사용하면 쿼리 실행 시간이 크게 단축됩니다.
정렬 작업 최적화 : 인덱스된 필드로 정렬할 때 성능이 향상됩니다.
고유성 보장 : 유니크 인덱스를 사용하여 필드 값의 중복을 방지할 수 있습니다.
집계 연산 개선 : 특정 집계 작업의 성능을 향상시킵니다.
자주 쿼리되는 데이터에 대해서는 컬렉션 자체를 계속적으로 조회하는 것은 성능 상으로 좋지 않습니다.
예를 들어 프로파일링 설정을 진행한 후 ,
참고 : 2024.08.26 - [MongoDB/성능] - MongoDB 성능 개선을 위한 점검 (DB 프로파일링 / db.setProfilingLevel)
system.profile 컬렉션 에서 다음과 같은 데이터가 출력되었다고 하자
{
"op" : "command",
"ns" : "platform.archive",
"command" : {
"aggregate" : "archive",
"pipeline" : [
{
"$match" : {
"$and" : [
{
"postId" : ObjectId("6614d8eed42b7bdeccef0d9b")
},
{
"createdAt" : {
"$gte" : ISODate("2024-04-16T00:00:00.000+0000")
}
},
{
"userStatus" : "block"
}
]
}
},
{
"$group" : {
"_id" : NumberInt(1),
"n" : {
"$sum" : NumberInt(1)
}
}
}
],
"cursor" : {
},
"lsid" : {
"id" : UUID("5e0c946a-b9f0-4926-816c-15df7cce19ca")
},
"$db" : "platform",
"$readPreference" : {
"mode" : "primaryPreferred"
}
},
"keysExamined" : NumberInt(0),
"docsExamined" : NumberInt(720633),
"cursorExhausted" : true,
"numYield" : NumberInt(720),
"nreturned" : NumberInt(0),
"queryHash" : "7A94B51E",
"planCacheKey" : "7A94B51E",
"queryFramework" : "classic",
"locks" : {
"FeatureCompatibilityVersion" : {
"acquireCount" : {
"r" : NumberLong(723)
}
},
"ReplicationStateTransition" : {
"acquireCount" : {
"w" : NumberLong(1)
}
},
"Global" : {
"acquireCount" : {
"r" : NumberLong(723)
}
},
"Mutex" : {
"acquireCount" : {
"r" : NumberLong(2)
}
}
},
"flowControl" : {
},
"storage" : {
},
"responseLength" : NumberInt(103),
"protocol" : "op_msg",
"millis" : NumberInt(467),
"planSummary" : "COLLSCAN",
"ts" : ISODate("2024-04-16T00:13:54.282+0000"),
"client" : "127.0.0.1",
"allUsers" : [
{
"user" : "user",
"db" : "admin"
}
],
"user" : "user@admin"
}
millis 속성을 보면 쿼리 실행에 대한 결과 출력에 467 ms가 걸렸다는 것과, planSummary 속성에서는 “COLLSCAN” 으로 collection scan을 실시했다는 것을 알 수 있습니다.
즉, 위 쿼리 pipeline 이 주기적으로 자주 실행되는데 collection scan을 통해서 전체 컬렉션을 조회하므로 성능적으로 많은 리소스를 사용하는 것.
해당 쿼리에 대해서는 인덱싱 을 적용하면 성능을 개선할 수 있습니다.(검색 효율 상승)
인덱싱 적용 코드
# archive 컬렉션에 대해서 postId, userStatus, createdAt 순으로 인덱싱하는 인덱스를 추가한 코드 예시
#db.{컬렉션명}.createIndex({"컬럼명1": 1, "컬럼명2": 1, ...);
db.archive.createIndex({"postId": 1, "userStatus": 1, "createdAt": 1});
인덱싱을 적용할 때는 반드시 쿼리문에서 조건 순서와 동일하게 인덱싱을 맞춰야 합니다.
그래야 mongodb에서 해당 인덱스를 쿼리에 사용합니다.(인덱싱이 효율적이지 않은 경우 mongodb 가 자체 판단하여 해당 인덱스를 사용하지 않음)
추가 MongoDB 인덱스 사용법
1. 단일 필드 인덱스 생성
가장 기본적인 형태의 인덱스입니다.
db.users.createIndex({ username: 1 })
이 명령어는 'users' 컬렉션의 'username' 필드에 오름차순 인덱스를 생성합니다.
2. 복합 인덱스 생성
두 개 이상의 필드를 조합한 인덱스입니다.
db.products.createIndex({ category: 1, price: -1 })
'category'는 오름차순, 'price'는 내림차순으로 정렬된 복합 인덱스가 생성됩니다.
3. 고유 인덱스 생성
중복 값을 허용하지 않는 인덱스입니다.
db.employees.createIndex({ email: 1 }, { unique: true })
이메일 주소의 유일성을 보장합니다.
4. TTL (Time-To-Live) 인덱스
일정 시간이 지나면 문서를 자동으로 삭제하는 인덱스입니다.
db.sessions.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
'createdAt' 필드를 기준으로 1시간 후 문서가 자동 삭제됩니다.
5. 텍스트 인덱스
전문 검색을 위한 인덱스입니다.
db.articles.createIndex({ content: "text" })
'content' 필드에 대한 텍스트 검색이 가능해집니다.
인덱스 사용 시 주의사항
과도한 인덱스 생성 자제 : 인덱스도 저장 공간을 차지하며, 쓰기 작업 시 오버헤드가 발생합니다.
쓰기 작업 고려 : 인덱스가 많을수록 INSERT, UPDATE, DELETE 작업의 속도가 느려질 수 있습니다.
정기적인 인덱스 분석 : explain() 명령어를 사용하여 쿼리 성능을 분석하고, 불필요한 인덱스는 제거하세요.
대용량 데이터셋 고려 : 매우 큰 컬렉션에 인덱스를 생성할 때는 백그라운드 옵션을 사용하세요.
db.hugecollection.createIndex({ field: 1 }, { background: true })