简体   繁体   English

Mongodb查询不使用复合索引上的前缀和文本字段

[英]Mongodb query does not use prefix on compound index with text field

I've created the following index on my collection: 我在我的集​​合上创建了以下索引:

db.myCollection.createIndex({
  user_id: 1,
  name: 'text'
})

If I try to see the execution plan of a query containing both fields, like this: 如果我试图查看包含两个字段的查询的执行计划,如下所示:

db.getCollection('campaigns').find({ 
    user_id: ObjectId('xxx')
   ,$text: { $search: 'bla' } 
}).explain('executionStats')

I get the following results: 我得到以下结果:

...
"winningPlan" : {
    "stage" : "TEXT",
    "indexPrefix" : {
        "user_id" : ObjectId("xxx")
    },
    "indexName" : "user_id_1_name_text",
    "parsedTextQuery" : {
        "terms" : [ 
            "e"
        ],
        "negatedTerms" : [],
        "phrases" : [],
        "negatedPhrases" : []
    },
    "inputStage" : {
        "stage" : "TEXT_MATCH",
        "inputStage" : {
            "stage" : "TEXT_OR",
            "inputStage" : {
                "stage" : "IXSCAN",
                "keyPattern" : {
                    "user_id" : 1.0,
                    "_fts" : "text",
                    "_ftsx" : 1
                },
                "indexName" : "user_id_1_name_text",
                "isMultiKey" : true,
                "isUnique" : false,
                "isSparse" : false,
                "isPartial" : false,
                "indexVersion" : 1,
                "direction" : "backward",
                "indexBounds" : {}
            }
        }
    }
}
...

As stated in the documentation , MongoDB can use index prefixes to perform indexed queries. 文档中所述,MongoDB可以使用索引前缀来执行索引查询。

Since user_id is a prefix for the index above, I'd expect that a query only by user_id would use the index, but if I try the following: 由于user_id是上面索引的前缀,我希望只有user_id的查询才会使用索引,但如果我尝试以下操作:

db.myCollection.find({ 
    user_id: ObjectId('xxx')
}).explain('executionStats')

I get: 我明白了:

...
"winningPlan" : {
    "stage" : "COLLSCAN",
    "filter" : {
        "user_id" : {
            "$eq" : ObjectId("xxx")
        }
    },
    "direction" : "forward"
},
...

So, it is not using the index at all and performing a full collection scan. 因此,它根本不使用索引并执行完整的集合扫描。

In general MongoDB can use index prefixes to support queries, however compound indexes including geospatial or text fields are a special case of sparse compound indexes . 通常,MongoDB可以使用索引前缀来支持查询,但是复合索引(包括地理空间或文本字段)是稀疏复合索引的特例。 If a document does not include a value for any of the text index field(s) in a compound index, it will not be included in the index. 如果文档不包含复合索引中任何文本索引字段的值,则它不会包含在索引中。

In order to ensure correct results for a prefix search, an alternative query plan will be chosen over the sparse compound index: 为了确保前缀搜索的正确结果 ,将在稀疏复合索引上选择备用查询计划:

If a sparse index would result in an incomplete result set for queries and sort operations, MongoDB will not use that index unless a hint() explicitly specifies the index. 如果稀疏索引会导致查询和排序操作的结果集不完整,MongoDB将不会使用该索引,除非提示()显式指定索引。

Setting up some test data in MongoDB 3.4.5 to demonstrate the potential problem: 在MongoDB 3.4.5中设置一些测试数据以演示潜在的问题:

db.myCollection.createIndex({ user_id:1, name: 'text' }, { name: 'myIndex'})

// `name` is a string; this document will be included in a text index
db.myCollection.insert({ user_id:123, name:'Banana' })

// `name` is a number; this document will NOT be included in a text index
db.myCollection.insert({ user_id:123, name: 456 })

// `name` is missing; this document will NOT be included in a text index
db.myCollection.insert({ user_id:123 })

Then, forcing the compound text index to be used: 然后,强制使用复合文本索引:

db.myCollection.find({user_id:123}).hint('myIndex')

The result only includes the single document with the indexed text field name , rather than the three documents that would be expected: 结果只包括带有索引文本字段name的单个文档,而不是预期的三个文档:

{
  "_id": ObjectId("595ab19e799060aee88cb035"),
  "user_id": 123,
  "name": "Banana"
}

This exception should be more clearly highlighted in the MongoDB documentation; 应在MongoDB文档中更清楚地突出显示此异常; watch/upvote DOCS-10322 in the MongoDB issue tracker for updates. 观察/ upvote DOCS-10322在MongoDB问题跟踪器中进行更新。

This behavior is due to text indexes being sparse by default : 此行为是由于默认情况下文本索引是稀疏的

For a compound index that includes a text index key along with keys of other types, only the text index field determines whether the index references a document. 对于包含文本索引键和其他类型键的复合索引,只有文本索引字段确定索引是否引用文档。 The other keys do not determine whether the index references the documents or not. 其他键不确定索引是否引用文档。

The query filter is not referencing the text index field, so the query planner won't consider this index as it can't be certain that the full result set of documents will be returned by the index. 查询过滤器未引用文本索引字段,因此查询规划器不会考虑此索引,因为无法确定索引将返回完整的文档结果集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM