基于查询语法未使用子文档的 MongoDB 索引

Posted

技术标签:

【中文标题】基于查询语法未使用子文档的 MongoDB 索引【英文标题】:MongoDB indexes on subdocuments not being used based on syntax of query 【发布时间】:2016-08-24 19:22:12 【问题描述】:

我正在将 Meteor 与 MongoDB 一起使用,其中包含这样的文档集合:

a: 'a1',
 b: 'b1',
 c: 
     d: 'd1',
     e: 'e1'
    

我最初创建的索引是这样的: collection._ensureIndex('c.d': 1);

然后运行这样的查询: collection.find(c: d: 'd1')。这些运行非常缓慢,当我使用 explain() 进行调试时,我意识到它们没有使用索引。

OTOH,如果我运行这样的查询: collection.find('c.d': 'd1'),那么 Mongo 使用索引。

我现在已更改索引以索引整个子文档,即collection._ensureIndex(c: 1),第一个查询现在命中索引。

我的问题是,这是错误还是功能?我的印象是,在 JSON 中,这两种表示法是等价的,坦率地说,我希望数据库足够聪明,能够判断出这两个查询词指的是同一个字段并使用适当的索引。

我对索引整个子文档的解决方法的担忧是,最终,该子文档可能包含更多我不需要索引的字段,而且浪费时间和 RAM 保存我不需要的索引项似乎不是最佳选择。

如果这不是错误,有没有办法让 Mongo 识别嵌套对象语法并正确使用索引?

【问题讨论】:

【参考方案1】:

我想我是在检查了 mongo 文档后才弄明白的。基本上,这两者之间在语义上存在差异。本质上,在查询c: d: d1 的第一种形式中,mongo 假定您正在指定整个 子文档。所以如果你有一个子文档c: d: d1, e: e1,它就不会匹配。

OTOH,查询'c.d': d1 的第二种形式意味着您只在子文档中的一个字段上指定匹配项。即使子文档有其他字段或整个子子文档,这也会匹配。

这种差异延伸到索引。 _ensureIndex(c: 1)_ensureIndex('c.d': 1) 是两个不同的索引,即使第一个索引整个子文档,如果您使用 c.d 表示法查询单个字段,它也不会被使用。

【讨论】:

以上是关于基于查询语法未使用子文档的 MongoDB 索引的主要内容,如果未能解决你的问题,请参考以下文章

基于多个子文档的MongoDB/Mongoose查询

MongoDB警告查询不使用索引

mongodb基础学习5

mongoDB_08索引的操作

MongoDB/Mongoose - 与 geoNear 和子文档的聚合

Mongodb体系结构 文档操作 索引 分析查询性能