2015-01-27 3 views
0

내 질문과 가장 관련이있는 문서의 배경은 this page on multikey index bounds and index intersection입니다.mongodb 멀티 키 색인 범위 내 서브 배열 배열

mongo가 서브 도메인 배열의 필드에서 $ elemMatch 쿼리의 인덱스 경계를 ​​제대로 결합하지 않는 것처럼 보이는 문제가 있습니다.

문서에서 내 특정 유스 케이스가 작동해서는 안되며 많은 일들이 내가하는 일에 매우 가깝다 고 말할 수 없습니다. 기술적 인 관점에서 나는 이것이 작동하지 않아야하는 이유를 생각해 낼 수 없다. 내가 뭔가를 놓친 건지 또는 누군가가 나에게 이것이 왜 그런 식으로 행동하는지 설명 할 수 있습니까?

mongos> db.test.findOne() 
{ 
    "_id" : ObjectId("54c7fdaa9a9950e75fa616b9"), 
    "data" : [ 
      { 
        "point" : 1, 
        "other" : "what" 
      } 
    ] 
} 

이 같은 장소에서 인덱스가 :

이 같은 문서의 모음으로 시작하고

mongos> db.test.getIndexes() 
[ 
    { 
      "v" : 1, 
      "key" : { 
        "_id" : 1 
      }, 
      "name" : "_id_", 
      "ns" : "temp.test" 
    }, 
    { 
      "v" : 1, 
      "key" : { 
        "data.point" : 1 
      }, 
      "name" : "data.point_1", 
      "ns" : "temp.test" 
    } 
] 

데이터 배열은 이런 식으로 하나 subdoc있다 :

mongos> db.test.find() 
{ "_id" : ObjectId("54c7fdaa9a9950e75fa616b9"), "data" : [ { "point" : 1, "other" : "what" } ] } 
{ "_id" : ObjectId("54c7fdaf9a9950e75fa616ba"), "data" : [ { "point" : 2, "other" : "who" } ] } 
{ "_id" : ObjectId("54c7fdb59a9950e75fa616bb"), "data" : [ { "point" : 3, "other" : "where" } ] } 
데이터에

$ elemMatch 쿼리가 잘 작동 :

mongos> db.test.find({data: {$elemMatch: {point: {$gte: 2, $lte: 2}}}}) 
{ "_id" : ObjectId("54c7fdaf9a9950e75fa616ba"), "data" : [ { "point" : 2, "other" : "who" } ] } 

mongos> db.test.find({data: {$elemMatch: {point: {$gte: 2, $lte: 2}}}}).explain(true) 
{ 
    "cursor" : "BtreeCursor data.point_1", 
    "isMultiKey" : false, 
    "n" : 1, 
    "nscannedObjects" : 1, 
    "nscanned" : 1, 
    "nscannedObjectsAllPlans" : 1, 
    "nscannedAllPlans" : 1, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 0, 
    "indexBounds" : { 
      "data.point" : [ 
        [ 
          2, 
          2 
        ] 
      ] 
    }, 
    "allPlans" : [ 
      { 
        "cursor" : "BtreeCursor data.point_1", 
        "isMultiKey" : false, 
        "n" : 1, 
        "nscannedObjects" : 1, 
        "nscanned" : 1, 
        "scanAndOrder" : false, 
        "indexOnly" : false, 
        "nChunkSkips" : 0, 
        "indexBounds" : { 
          "data.point" : [ 
            [ 
              2, 
              2 
            ] 
          ] 
        } 
      } 
    ], 
    "server" : "XXXXXX", 
    "filterSet" : false, 
    "stats" : { 
      "type" : "KEEP_MUTATIONS", 
      "works" : 2, 
      "yields" : 0, 
      "unyields" : 0, 
      "invalidates" : 0, 
      "advanced" : 1, 
      "needTime" : 0, 
      "needFetch" : 0, 
      "isEOF" : 1, 
      "children" : [ 
        { 
          "type" : "FETCH", 
          "works" : 2, 
          "yields" : 0, 
          "unyields" : 0, 
          "invalidates" : 0, 
          "advanced" : 1, 
          "needTime" : 0, 
          "needFetch" : 0, 
          "isEOF" : 1, 
          "alreadyHasObj" : 0, 
          "forcedFetches" : 0, 
          "matchTested" : 1, 
          "children" : [ 
            { 
              "type" : "IXSCAN", 
              "works" : 2, 
              "yields" : 0, 
              "unyields" : 0, 
              "invalidates" : 0, 
              "advanced" : 1, 
              "needTime" : 0, 
              "needFetch" : 0, 
              "isEOF" : 1, 
              "keyPattern" : "{ data.point: 1.0 }", 
              "isMultiKey" : 0, 
              "boundsVerbose" : "field #0['data.point']: [2.0, 2.0]", 
              "yieldMovedCursor" : 0, 
              "dupsTested" : 0, 
              "dupsDropped" : 0, 
              "seenInvalidated" : 0, 
              "matchTested" : 0, 
              "keysExamined" : 1, 
              "children" : [ ] 
            } 
          ] 
        } 
      ] 
    }, 
    "millis" : 0 
} 

하지만이처럼 data 배열 내부에 하나 이상의 subdoc에 문서를 추가 할 때 :

mongos> db.test.insert({data: [{point: 3, other: 'where'}, {point:4, other:"huh"}]}) 
WriteResult({ "nInserted" : 1 }) 
mongos> db.test.find() 
{ "_id" : ObjectId("54c7fdaa9a9950e75fa616b9"), "data" : [ { "point" : 1, "other" : "what" } ] } 
{ "_id" : ObjectId("54c7fdaf9a9950e75fa616ba"), "data" : [ { "point" : 2, "other" : "who" } ] } 
{ "_id" : ObjectId("54c7fdb59a9950e75fa616bb"), "data" : [ { "point" : 3, "other" : "where" } ] } 
{ "_id" : ObjectId("54c806c39a9950e75fa616bc"), "data" : [ { "point" : 3, "other" : "where" }, { "point" : 4, "other" : "huh" } ] } 

쿼리가 (이다 사소 시험의 경우) 이상 규모의 주문을 소요하고, true까지 [-Infinity, 2] 변경에게 적절한 [2, 2]에서 경계를 설명하고 isMultiKey 플래그 틱 :

mongos> db.test.find({data: {$elemMatch: {point: {$gte: 2, $lte: 2}}}}).explain(true) 
{ 
    "cursor" : "BtreeCursor data.point_1", 
    "isMultiKey" : true, 
    "n" : 1, 
    "nscannedObjects" : 2, 
    "nscanned" : 2, 
    "nscannedObjectsAllPlans" : 2, 
    "nscannedAllPlans" : 2, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 0, 
    "indexBounds" : { 
      "data.point" : [ 
        [ 
          -Infinity, 
          2 
        ] 
      ] 
    }, 
    "allPlans" : [ 
      { 
        "cursor" : "BtreeCursor data.point_1", 
        "isMultiKey" : true, 
        "n" : 1, 
        "nscannedObjects" : 2, 
        "nscanned" : 2, 
        "scanAndOrder" : false, 
        "indexOnly" : false, 
        "nChunkSkips" : 0, 
        "indexBounds" : { 
          "data.point" : [ 
            [ 
              -Infinity, 
              2 
            ] 
          ] 
        } 
      } 
    ], 
    "server" : "XXXXXX", 
    "filterSet" : false, 
    "stats" : { 
      "type" : "KEEP_MUTATIONS", 
      "works" : 3, 
      "yields" : 0, 
      "unyields" : 0, 
      "invalidates" : 0, 
      "advanced" : 1, 
      "needTime" : 1, 
      "needFetch" : 0, 
      "isEOF" : 1, 
      "children" : [ 
        { 
          "type" : "FETCH", 
          "works" : 3, 
          "yields" : 0, 
          "unyields" : 0, 
          "invalidates" : 0, 
          "advanced" : 1, 
          "needTime" : 1, 
          "needFetch" : 0, 
          "isEOF" : 1, 
          "alreadyHasObj" : 0, 
          "forcedFetches" : 0, 
          "matchTested" : 1, 
          "children" : [ 
            { 
              "type" : "IXSCAN", 
              "works" : 3, 
              "yields" : 0, 
              "unyields" : 0, 
              "invalidates" : 0, 
              "advanced" : 2, 
              "needTime" : 0, 
              "needFetch" : 0, 
              "isEOF" : 1, 
              "keyPattern" : "{ data.point: 1.0 }", 
              "isMultiKey" : 1, 
              "boundsVerbose" : "field #0['data.point']: [-inf.0, 2.0]", 
              "yieldMovedCursor" : 0, 
              "dupsTested" : 2, 
              "dupsDropped" : 0, 
              "seenInvalidated" : 0, 
              "matchTested" : 0, 
              "keysExamined" : 2, 
              "children" : [ ] 
            } 
          ] 
        } 
      ] 
    }, 
    "millis" : 0 
} 

그것은이다 여전히 올바른 btree 인덱스를 사용하고 올바른 결과를 얻지 만이 문제는 큰 데이터 세트에서 사용 가능하고 사용할 수없는 것의 차이입니다.

은 내가 사용하고 쿼리가이 동등 것을 알고 :

db.test.find({data: {$elemMatch: {point: 2}}}) 

하지만 편의상 그 일을 해요 - $의 GT는 $의 어떤 경계를 지정할 때 같은 동작이 관찰된다 gte $ lt $ lte는 인덱스 범위가 인덱스에 잘못 설정되어 있다는 것입니다.

: 나는 위의 쿼리를 수행 할 때의 몽고 내가 여러 subdocs의 배열을 사용하여 원하는 계획을 충족하는 쿼리를 발행 할 수 없습니다 좋아하지, 그래서 난 사실, 내가 기대 인덱스의 경계를 취득 참고로

,

{ 
    "cursor" : "BtreeCursor data.point_1", 
    "isMultiKey" : true, 
    "n" : 1, 
    "nscannedObjects" : 1, 
    "nscanned" : 1, 
    "nscannedObjectsAllPlans" : 1, 
    "nscannedAllPlans" : 1, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 0, 
    "indexBounds" : { 
      "data.point" : [ 
        [ 
          2, 
          2 
        ] 
      ] 
    }, 
    "allPlans" : [ 
      { 
        "cursor" : "BtreeCursor data.point_1", 
        "isMultiKey" : true, 
        "n" : 1, 
        "nscannedObjects" : 1, 
        "nscanned" : 1, 
        "scanAndOrder" : false, 
        "indexOnly" : false, 
        "nChunkSkips" : 0, 
        "indexBounds" : { 
          "data.point" : [ 
            [ 
              2, 
              2 
            ] 
          ] 
        } 
      } 
    ], 
    "server" : "XXXXXX", 
    "filterSet" : false, 
    "stats" : { 
      "type" : "KEEP_MUTATIONS", 
      "works" : 2, 
      "yields" : 0, 
      "unyields" : 0, 
      "invalidates" : 0, 
      "advanced" : 1, 
      "needTime" : 0, 
      "needFetch" : 0, 
      "isEOF" : 1, 
      "children" : [ 
        { 
          "type" : "FETCH", 
          "works" : 2, 
          "yields" : 0, 
          "unyields" : 0, 
          "invalidates" : 0, 
          "advanced" : 1, 
          "needTime" : 0, 
          "needFetch" : 0, 
          "isEOF" : 1, 
          "alreadyHasObj" : 0, 
          "forcedFetches" : 0, 
          "matchTested" : 1, 
          "children" : [ 
            { 
              "type" : "IXSCAN", 
              "works" : 2, 
              "yields" : 0, 
              "unyields" : 0, 
              "invalidates" : 0, 
              "advanced" : 1, 
              "needTime" : 0, 
              "needFetch" : 0, 
              "isEOF" : 1, 
              "keyPattern" : "{ data.point: 1.0 }", 
              "isMultiKey" : 1, 
              "boundsVerbose" : "field #0['data.point']: [2.0, 2.0]", 
              "yieldMovedCursor" : 0, 
              "dupsTested" : 1, 
              "dupsDropped" : 0, 
              "seenInvalidated" : 0, 
              "matchTested" : 0, 
              "keysExamined" : 1, 
              "children" : [ ] 
            } 
          ] 
        } 
      ] 
    }, 
    "millis" : 0 
} 

... 다시 - 내가 뭔가를 놓쳤습니까? 내가 잘못하고 있니? 해결 방법이 있습니까? 이 버그 또는 알려진 문제입니까?

나는 mongodb v2.6.5를 샤드 복제 된 cluseter에서 사용하고 있습니다.

답변