인덱스를 만들었다면, 해당 인덱스를 mongoDB가 활용하고 있는 지를 체크해야 한다.
explain
find와 aggregate에서 explain하는 방식이 조금 다릅니다.
db.by_type.find().explain()
db.by_type..explain().aggregate([])
다음과 같이 쿼리 조건문을 이용하여 특정 정보를 find한 후에 explain()을 하였다.
db.by_type.find(
{type: "차대차", accident_count: {$gte: 100}, death_toll: 0},
{city_or_province: 1, county: 1}
).explain()
어떤 과정을 거쳐 쿼리가 진행되었는지 내역을 표시해준다.
여기서 우리가 쿼리 실행 속도를 위해 눈 여겨 볼 곳은 winningPlan이다.
winningPlan은 쿼리를 실행하는 가장 효율적인 계획을 말하며, 인덱스를 사용했다면 이 부분을 참고하여 인덱스를 사용했는지, 아닌지를 참고할 수 있다.
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "car_accident.by_type",
"indexFilterSet" : false,
"parsedQuery" : {
.... 생략
},
"queryHash" : "638C6F98",
"planCacheKey" : "638C6F98",
// winningPlan을 참고해보자
"winningPlan" : {
"stage" : "PROJECTION_SIMPLE",
"transformBy" : {
"city_or_province" : 1.0,
"county" : 1.0
},
"inputStage" : {
"stage" : "COLLSCAN",
"filter" : {
... 생략
},
"direction" : "forward"
}
},
"rejectedPlans" : []
},
"serverInfo" : {
... 서버에 대한 정보들
},
"ok" : 1.0
}
여기서 stage 부분을 차례대로 살펴보면 다음 순으로 되어 있다. 실행 순서는 역순이다.
"stage" : "PROJECTION_SIMPLE",
"stage" : "COLLSCAN",
위 쿼리를 수행하는 방법이 COLLSCAN => PROJECTION_SIMPLE 으로 이루어 졌다는 것이다.
이 말인 즉슨, 컬렉션 전체를 스캔 한 후 projection을 위해 필요한 필드만 남기고 다른 필드를 삭제했다는 것이다.
컬렉션 전체를 스캔했다는 것은 인덱스를 사용하지 않은 쿼리 탐색을 실행했다는 것이다.
인덱스가 사용되었다면 IXSCAN이 보여야 한다.
COLLSCAN : 컬렉션 전체 스캔
IXSCAN : 인덱스 키 스캔
FETCH : 도큐먼트를 불러온다
UPDATE : 도큐먼트를 수정한다
SORT : 도큐먼트를 정렬한다
PROJECTION : projection을 위해 일부 필드만 남기고 다른 필드를 삭제한다.
SHARD_MERGE : 샤딩되어 흩어진 정보를 모은다.
db.by_type.createIndex({accident_count: 1})
db.by_type.find(
{type: "차대차", accident_count: {$gte: 100}, death_toll: 0},
{city_or_province: 1, county: 1}
).explain()
위와 같이 인덱스를 설정한 후 explain을 해보았습니다. 이제는 IXSCAN이 뜨네요
"stage" : "FETCH",
"stage" : "IXSCAN",
이 말은, IXSCAN(인덱스를 살피고), FETCH(필요한 정보만 불러옴) 순으로 쿼리가 실행되었다는 것입니다.
{
"queryPlanner" : {
"winningPlan" : {
"stage" : "PROJECTION_SIMPLE",
"transformBy" : {
"city_or_province" : 1.0,
"county" : 1.0
},
"inputStage" : {
"stage" : "FETCH",
"filter" : {
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"accident_count" : 1.0
},
"indexName" : "accident_count_1", // 사용한 인덱스의 이름
"isMultiKey" : false, // multi key입니까?
"multiKeyPaths" : {
"accident_count" : []
},
"isUnique" : false, // unique 인덱스입니까?
"isSparse" : false, // sparse 인덱스입니까?
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"accident_count" : [
"[100.0, inf.0]"
]
}
}
}
},
"rejectedPlans" : []
},
"ok" : 1.0
}
하나의 쿼리 명령은 explain을 통해 그 내역을 살필 수 있지만 실제 서비스가 운영중이라면 프로파일러를 이용하는 것이 좋습니다.
'DB, ORM > 🍃 mongoDB (shell)' 카테고리의 다른 글
mongoDB Atlas와 Robo3T 연결 (0) | 2020.12.15 |
---|---|
고가용성을 위한 mongoDB Replication (1) : P, S, A와 선거 (0) | 2020.07.25 |
인덱스 (2) 인덱스 명령어 (0) | 2020.07.25 |
인덱스 (1) 인덱싱의 이해, 종류, B-Tree 자료구조 (0) | 2020.07.25 |
집계 명령어 활용하기 (3) Aggregate 파이프라인 (ii) 👨🏫 고급(?) stage (0) | 2020.07.25 |