내 질문과 가장 관련이있는 문서의 배경은 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에서 사용하고 있습니다.