mongodb索引已创建,但在查询过程中未使用

mongodb索引已创建,但在查询过程中未使用,mongodb,Mongodb,希望这不是一个完全愚蠢的问题。 我正在mongodb上创建一个包含字符串的字段的复合索引。 在运行索引创建之后,我没有看到通过db.currentOp()创建索引的进程,但是如果运行getIndexes(),我确实看到了索引 使用explain I always get COLLSCAN运行此查询我从未看到索引扫描而不是COLLSCAN: db.sampledb.aggregate([ { "$match": { "D

希望这不是一个完全愚蠢的问题。 我正在mongodb上创建一个包含字符串的字段的复合索引。 在运行索引创建之后,我没有看到通过db.currentOp()创建索引的进程,但是如果运行getIndexes(),我确实看到了索引

使用explain I always get COLLSCAN运行此查询我从未看到索引扫描而不是COLLSCAN:

db.sampledb.aggregate([
    {
        "$match": {
            "DevIdent.ParametersExt.ID": { "$regex": ".*22~44.*" },
            "DevIdent.Parameters.Type": { "$ne": "TYPICAL" },
            "MetaData.SessionName": "2021_02_09_13_31_03"
        }
    }
])

我缺少一些基本的东西吗?

这个匹配的过滤器就是问题所在:

"DevIdent.ParametersExt.ID": { "$regex": ".*22~44.*" }
您正在
DevIdent.parameters sext.ID
字段中的任何位置搜索文本
22~44
。问题是,仅当搜索可以从字段的最开头开始时,才可以使用基于B树的索引,而这里的情况并非如此

但是,没有理由不在其他两个字段上使用索引。但是,由于您在无法使用的字段上启动了多列索引,因此Mongo选择完全不使用此索引

您可以考虑只定义其他两个字段的索引:

db.sampledb.createIndex({
“偏差参数类型”:1,
“MetaData.SessionName”:1
},
{
背景:错,
名称:“样本”,
});

假设这两个字段具有很高的基数(即限制性很强),那么Mongo可以选择使用索引,尽管第三个字段上有regex条件。

索引只能用于“前缀”
^……
regexp。我发现位于的文档非常清楚,因此我将在此处引用它:

对于区分大小写的正则表达式查询,如果存在 字段,然后MongoDB将正则表达式与 索引中的值,这可能比集合扫描快。 如果正则表达式是“前缀”,则可以进行进一步优化 表达式”,这意味着所有可能的匹配都以 相同的字符串。这允许MongoDB从中构造一个“范围” 前缀,并且仅与索引中的值匹配 在这个范围内

如果正则表达式以 插入符号(^)或左锚(\a),后跟一个简单 符号。例如,regex/^abc.*/将通过匹配进行优化 仅针对以abc开头的索引中的值

另外,/^a/、/^a./、和/^a.$/匹配等效项 字符串,它们具有不同的性能特征。所有这些 如果存在适当的索引,表达式将使用索引;然而, /^a、 /、和/^a.$/的速度较慢/^a/匹配后可以停止扫描 前缀


每个人发布的答案对于索引的低效使用都是正确的,但在解释计划中它仍然应该被理解为IXSCAN,所以我做了一个测试

db.sampledb.createIndex(
    {
        "DevIdent.ParametersExt. ID": 1,
        "DevIdent.Parameters.Type": 1,
        "MetaData.SessionName": 1
    },
    {
        background: false,
        name: "sample",
    }
)
这是您的命令,
DevIdent.ParametersExt.&ID
,导致出现问题,但您仍然无法在没有空格的情况下创建新索引,因此出现重复错误。一起删除此索引并创建一个没有空格的新索引

编辑:学童错误,删除名字部分,你应该能够 创建这两个索引,在树中,它只是字段名 使用相应的BSON类型存储的字符串,因此使用 空格和不空格分别是两个索引

现在试试你的聚合命令,对我有用

{
"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "test_content.test4",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "$and" : [ 
            {
                "MetaData.SessionName" : {
                    "$eq" : "2021_02_09_13_31_03"
                }
            }, 
            {
                "DevIdent.ParametersExt.ID" : {
                    "$regex" : ".*22~44.*"
                }
            }, 
            {
                "DevIdent.Parameters.Type" : {
                    "$not" : {
                        "$eq" : "TYPICAL"
                    }
                }
            }
        ]
    },
    "optimizedPipeline" : true,
    "winningPlan" : {
        "stage" : "FETCH",
        "inputStage" : {
            "stage" : "IXSCAN",
            "filter" : {
                "DevIdent.ParametersExt.ID" : {
                    "$regex" : ".*22~44.*"
                }
            },
            "keyPattern" : {
                "DevIdent.ParametersExt.ID" : 1.0,
                "DevIdent.Parameters.Type" : 1.0,
                "MetaData.SessionName" : 1.0
            },
            "indexName" : "sample",
            "isMultiKey" : false,
            "multiKeyPaths" : {
                "DevIdent.ParametersExt.ID" : [],
                "DevIdent.Parameters.Type" : [],
                "MetaData.SessionName" : []
            },
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                "DevIdent.ParametersExt.ID" : [ 
                    "[\"\", {})", 
                    "[/.*22~44.*/, /.*22~44.*/]"
                ],
                "DevIdent.Parameters.Type" : [ 
                    "[MinKey, \"TYPICAL\")", 
                    "(\"TYPICAL\", MaxKey]"
                ],
                "MetaData.SessionName" : [ 
                    "[\"2021_02_09_13_31_03\", \"2021_02_09_13_31_03\"]"
                ]
            }
        }
    },

这是正确的,但请注意,如果OP将regex字段放在索引的最后一个,Mongo仍然可以通过在过滤前两个字段后选择扫描来使用此多列索引。因此,如果使用不同的措辞,索引可能会被使用。@TimBiegeleisen
DevIdent.ParametersExt。ID
首先查看问题的当前版本。我完全同意,如果它是索引定义中的最后一个,那么可以使用该索引。当然,假设空格是问题中的一个输入错误。是的,空格只是stackoverflow的一个复制错误,因为我将字段的名称改短了,以减少问题的混淆,并最终导致更多的混淆,很抱歉,我以前在文档中没有遇到regex前缀问题,感谢您指出这是一个很好的帮助您完全正确,因为索引是在不同的集合上创建的,它不起作用,但我遇到的下一个问题是正则表达式问题,因此我们需要重新设计数据,以显示在字段的开头,以便进行有效的索引,最后每个人都是正确的,真的很有帮助,非常感谢@AnatolyZaretsky如果您不介意接受正确答案,请基本上标记它。我以前在文档中没有遇到regex前缀问题,感谢您指出这是一个很大的帮助!!
db.sampledb.createIndex(
    {
        "DevIdent.ParametersExt.ID": 1,
        "DevIdent.Parameters.Type": 1,
        "MetaData.SessionName": 1
    },
    {
        background: false,
        name: "sample",
    }
)  
{
"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "test_content.test4",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "$and" : [ 
            {
                "MetaData.SessionName" : {
                    "$eq" : "2021_02_09_13_31_03"
                }
            }, 
            {
                "DevIdent.ParametersExt.ID" : {
                    "$regex" : ".*22~44.*"
                }
            }, 
            {
                "DevIdent.Parameters.Type" : {
                    "$not" : {
                        "$eq" : "TYPICAL"
                    }
                }
            }
        ]
    },
    "optimizedPipeline" : true,
    "winningPlan" : {
        "stage" : "FETCH",
        "inputStage" : {
            "stage" : "IXSCAN",
            "filter" : {
                "DevIdent.ParametersExt.ID" : {
                    "$regex" : ".*22~44.*"
                }
            },
            "keyPattern" : {
                "DevIdent.ParametersExt.ID" : 1.0,
                "DevIdent.Parameters.Type" : 1.0,
                "MetaData.SessionName" : 1.0
            },
            "indexName" : "sample",
            "isMultiKey" : false,
            "multiKeyPaths" : {
                "DevIdent.ParametersExt.ID" : [],
                "DevIdent.Parameters.Type" : [],
                "MetaData.SessionName" : []
            },
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 2,
            "direction" : "forward",
            "indexBounds" : {
                "DevIdent.ParametersExt.ID" : [ 
                    "[\"\", {})", 
                    "[/.*22~44.*/, /.*22~44.*/]"
                ],
                "DevIdent.Parameters.Type" : [ 
                    "[MinKey, \"TYPICAL\")", 
                    "(\"TYPICAL\", MaxKey]"
                ],
                "MetaData.SessionName" : [ 
                    "[\"2021_02_09_13_31_03\", \"2021_02_09_13_31_03\"]"
                ]
            }
        }
    },