Computer >> 컴퓨터 >  >> 프로그래밍 >> MongoDB

MongoDB에서 $or 연산자가 포함된 쿼리도 인덱스를 사용할 수 있을까요?

네, 가능합니다. MongoDB에서 $or 연산자가 포함된 쿼리도 각 조건에 해당하는 필드에 인덱스가 미리 생성되어 있다면 인덱스를 활용할 수 있습니다. 핵심은 $or 절 안의 각 필드마다 개별적인 인덱스를 만들어 두는 것입니다.

이번 글에서는 실제 예제를 통해 인덱스를 생성하고, explain() 메서드로 실행 계획을 확인하며 인덱스가 실제로 사용되는지 검증해 보겠습니다.

1단계: 인덱스 생성하기

먼저 $or 조건에서 사용될 첫 번째 필드인 First에 오름차순(1) 인덱스를 생성합니다.

> db.indexOrQueryDemo.createIndex({"First":1});

위 명령을 실행하면 다음과 같은 결과가 출력됩니다.

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 2,
    "numIndexesAfter" : 3,
    "ok" : 1
}

numIndexesBefore는 인덱스 생성 전 개수, numIndexesAfter는 생성 후 개수를 의미합니다. 위 결과를 보면 인덱스가 하나 추가되어 2개에서 3개로 늘어난 것을 확인할 수 있습니다.

이어서 두 번째 필드인 Second에도 동일한 방식으로 인덱스를 생성합니다.

> db.indexOrQueryDemo.createIndex({"Second":1});

실행 결과는 다음과 같습니다.

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 3,
    "numIndexesAfter" : 4,
    "ok" : 1
}

이제 FirstSecond 필드 각각에 대한 인덱스가 모두 준비되었습니다.

2단계: $or 연산자 쿼리에 explain() 적용하기

인덱스가 실제로 사용되는지 확인하려면 $or 연산자가 포함된 쿼리 뒤에 explain() 메서드를 붙여 실행 계획(plan)을 조회하면 됩니다.

> db.indexOrQueryDemo.find({$or:[{First:1}, {Second:2}]}).explain();

실행 결과의 주요 부분은 다음과 같습니다.

{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "test.indexOrQueryDemo",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$or" : [
                {
                    "First" : {
                        "$eq" : 1
                    }
                },
                {
                    "Second" : {
                        "$eq" : 2
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "SUBPLAN",
            "inputStage" : {
                "stage" : "FETCH",
                "inputStage" : {
                    "stage" : "OR",
                    "inputStages" : [
                        {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "First" : 1
                            },
                            "indexName" : "First_1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "First" : [ ]
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "First" : [
                                    "[1.0, 1.0]"
                                ]
                            }
                        },
                        {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "Second" : 1
                            },
                            "indexName" : "Second_1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "Second" : [ ]
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "forward",
                            "indexBounds" : {
                                "Second" : [
                                    "[2.0, 2.0]"
                                ]
                            }
                        }
                    ]
                }
            }
        },
        "rejectedPlans" : [ ]
    },
    "serverInfo" : {
        "host" : "DESKTOP-QN2RB3H",
        "port" : 27017,
        "version" : "4.0.5",
        "gitVersion" : "3739429dd92b92d1b0ab120911a23d50bf03c412"
    },
    "ok" : 1
}

실행 계획 결과 분석하기

출력 결과에서 가장 중요하게 살펴볼 부분은 winningPlan, 즉 MongoDB 쿼리 플래너가 최종적으로 선택한 실행 계획입니다.

  • SUBPLAN 단계: $or 연산자가 포함된 쿼리를 처리하기 위해 플래너가 하위 계획(subplan)을 구성했음을 의미합니다.
  • OR 단계: 두 개의 조건을 각각 처리한 후 결과를 병합하는 역할을 담당합니다.
  • IXSCAN 단계: 인덱스 스캔(Index Scan)을 나타냅니다. 이 단계가 보인다는 것은 컬렉션 전체를 훑는 COLLSCAN(전체 컬렉션 스캔)이 아니라 인덱스를 활용해 쿼리가 실행되었음을 의미합니다.

실제로 출력 결과를 보면 첫 번째 IXSCAN에서는 indexName: "First_1"이, 두 번째 IXSCAN에서는 indexName: "Second_1"이 사용된 것을 확인할 수 있습니다. 즉, $or 절의 각 조건이 서로 다른 인덱스로 효율적으로 처리된 것입니다.

정리 및 참고 사항

MongoDB에서 $or 쿼리가 인덱스를 제대로 활용하려면 다음 사항을 기억하세요.

  • $or 안의 모든 조건 필드에 각각 인덱스가 존재해야 인덱스가 사용됩니다. 하나라도 인덱스가 없으면 전체 쿼리가 컬렉션 스캔으로 fallback될 수 있습니다.
  • explain() 결과에서 IXSCAN 스테이지가 포함되어 있는지 확인하면 인덱스 사용 여부를 바로 판단할 수 있습니다.
  • 예제에 사용된 ensureIndex()는 현재 deprecated(사용 중단 권고)된 메서드이므로, 최신 버전의 MongoDB에서는 createIndex()를 사용하는 것이 좋습니다.