首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoDB在简单查找中不使用索引

MongoDB在简单查找中不使用索引
EN

Stack Overflow用户
提问于 2022-10-21 13:47:52
回答 1查看 19关注 0票数 0

我有一个名为"EN“的集合,我创建了一个索引如下:

代码语言:javascript
复制
db.EN.createIndex( { "Prod_id": 1 } );

当我运行db.EN.getIndexes()时,我得到了以下内容:

代码语言:javascript
复制
[{   "v": 2,   "key": {
    "_id": 1   },   "name": "_id_" }, {   "v": 2,   "key": {
    "Prod_id": 1   },   "name": "Prod_id_1" }]

但是,当我运行以下查询时:

代码语言:javascript
复制
    db.EN.find({'Icecat-interface.Product.@Prod_id':'ABCD'})
      .explain()

我明白了:

代码语言:javascript
复制
{   "explainVersion": "1",   "queryPlanner": {
    "namespace": "Icecat.EN",
    "indexFilterSet": false,
    "parsedQuery": {
      "ICECAT-interface.Product.Prod_id": {
        "$eq": "ABCD"
      }
    },
    "queryHash": "D12BE22E",
    "planCacheKey": "9F077ED2",
    "maxIndexedOrSolutionsReached": false,
    "maxIndexedAndSolutionsReached": false,
    "maxScansToExplodeReached": false,
    "winningPlan": {
      "stage": "COLLSCAN",
      "filter": {
        "ICECAT-interface.Product.Prod_id": {
          "$eq": "ABCD"
        }
      },
      "direction": "forward"
    },
    "rejectedPlans": []   },   "command": {
    "find": "EN",
    "filter": {
      "ICECAT-interface.Product.Prod_id": "ABCD"
    },
    "batchSize": 1000,
    "projection": {},
    "$readPreference": {
      "mode": "primary"
    },
    "$db": "Icecat"   },   "serverInfo": {

它使用的是COLLSCAN而不是索引,为什么会发生这种情况?

MongoDB版本为5.0.9-8

谢谢

编辑(和解决方案)

它的前面是字段名"@“,而索引是在没有这个字符的情况下创建的,所以根本没有捡到它。

有一次,我使用字段名创建了一个新的索引,就像它应该的那样,它正常工作。

不过,看到索引的工作原理和最佳实践是很有趣的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-21 14:08:39

查找操作定义为

代码语言:javascript
复制
.find({'Icecat-interface.Product.@Prod_id':'ABCD'})

什么是Icecat-interface.Product.@

explain输出中的parsedQuery确认MongoDB试图查找一个文档,该文档的值为"ABCD",其值与您所命名的字段名不同。根据您提供的explain,这个字段名是"ICECAT-interface.Product.Prod_id"。由于查询的字段名与索引的字段名不同,MongoDB无法使用索引执行操作。

与此略有关联的是,@输出中没有find中使用的explain字符。这似乎是因为用于生成explain的实际操作略有不同。这也是显而易见的事实,解释包括一个batchSize of 1000,该操作在被显示为被解释的操作中缺失。

根据Icecat-interface.Product.@前缀应该是什么,解决方案可能只是将其从find本身的查询谓词中删除。

编辑以响应comment和编辑问题。关于第一项评论:

当我运行

:.find({'Prod_id':'ABCD'})时,它使用COLLSCAN,这对我来说是错误的,因为我在该字段上有一个索引,除非我在这里遗漏了什么

如果查询使用了MongoDB的第一个键,那么它将使用索引。因此,{ y: 1 }上的索引不符合.find({ x: 1})查询的使用条件。类似于一般的xy示例,Icecat-interface.Product.Prod_idProd_id是不同的字段名。因此,如果您对一个查询而另一个查询只存在一个索引,则集合扫描是数据库执行该查询的唯一方法。

这将与问题的编辑部分重叠。在已编辑的问题中,新的解释计划使用索引成功地显示了数据库。但是,该索引是{ "ICECAT-interface.Product.Prod_id": 1 },它是,而不是--最初显示在集合({ "Prod_id": 1 })上创建或显示的索引。

此外,您还提到“即使我知道的产品在DB中,也不会得到任何结果”。数据库中的哪个字段包含正在搜索的值('ABCD')?这将直接告诉您返回的结果以及用于查找结果的索引。请记住,即使数据库中不存在任意字段,也可以搜索MongoDB中的任意字段。

我建议特别注意正在使用的名称空间和字段名。除非这个{ "ICECAT-interface.Product.Prod_id": 1 }索引是在收集db.EN.getIndexes()输出之后创建的,否则您可能无意中连接到不同的系统或名称空间,因为该索引肯定存在于某个地方。

在我写这篇文章的时候,基于你的live comments,你似乎已经解开了字段名的谜团。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74154625

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档