带有索引字段的 MongoDB 正则表达式

Posted

技术标签:

【中文标题】带有索引字段的 MongoDB 正则表达式【英文标题】:MongoDB regular expression with indexed field 【发布时间】:2011-12-27 18:30:28 【问题描述】:

我正在使用 MongoDB 创建我的第一个应用程序。 为字段创建索引,并尝试使用 $regex 参数进行查找查询,在 shell 中启动

> db.foo.find(A:$regex:'BLABLA!25500[0-9]').explain()

        "cursor" : "BtreeCursor A_1 multi",
        "nscanned" : 500001,
        "nscannedObjects" : 10,
        "n" : 10,
        "millis" : 956,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "isMultiKey" : false,
        "indexOnly" : false,
        "indexBounds" : 
                "A" : [
                        [
                                "",
                                

                                
                        ],
                        [
                                /BLABLA!25500[0-9]/,
                                /BLABLA!25500[0-9]/
                        ]
                ]
        

这很奇怪,因为当我启动相同的查询,但集合中没有索引时,性能要好得多。

> db.foo.find(A:$regex:'BLABLA!25500[0-9]').explain()

        "cursor" : "BasicCursor",
        "nscanned" : 500002,
        "nscannedObjects" : 500002,
        "n" : 10,
        "millis" : 531,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "isMultiKey" : false,
        "indexOnly" : false,
        "indexBounds" : 

        

显然,在没有正则表达式的情况下搜索具有索引的字段工作得更快(即搜索具有常量字段的文档),但我真的对这种行为的原因很感兴趣。

【问题讨论】:

不知道是什么导致索引变慢,但是如果您希望正则表达式利用索引,您可以尝试^BLABLA!25500[0-9] 让 mongodb 知道第一个字符是什么(如果它适合您的用例)。 有效!我怎么会忘记...现在只需要 49 毫秒。谢谢!但是我仍然不知道为什么索引会变慢,如果 mongo 知道它不能使用索引并在集合中处理完整搜索......它如何关心索引? ... @Lycha:这只是您做出的假设,并且是错误的:对索引字段执行正则表达式将使用该索引(不会扫描集合中的每个文档),即使正则表达式表达式没有说明前缀(即使正则表达式类似于 /.*whatever.*/) @AndreiBodnarescu 你在哪里读到的?根据表现,我的建议似乎是正确的。这是来自 mongodb 网站的引述“对于像 /^prefix/ 这样的简单前缀查询(也称为根正则表达式),数据库将在可用且适当时使用索引”。基于此,它只会将索引用于前缀正则表达式。 我一定在他们的文档中错过了这一点,但是进行一些基本测试表明,对于基本(如文本)索引字段,进行正则表达式搜索将始终使用索引,即使您指定前缀与否。只要您使用点表示法(不是 $elemMatch),嵌入式数组字段也是如此。所以基本上,就搜索中的索引使用而言,如果您指定一个带有前缀或不带前缀的正则表达式,那么它是没有意义的 【参考方案1】:

这里性能差异的原因很可能是,启用索引后,您的查询必须遍历索引(加载到内存中),然后将匹配的文档也加载到内存中。由于您没有使用前缀查询,索引中的所有值都将被扫描并针对正则表达式进行测试。效率不高。

当您删除索引时,您只是在进行表扫描并在那里匹配正则表达式 - 基本上您从第一个中稍微简化了一些事情。

如果它是 covered index query,您可能可以使索引版本更快,如果这是一个复合索引并且您需要将它与另一个字段的条件结合起来,它也可能会更快。

当您使用前缀查询时,并不是它只使用索引,而是您有效地使用了索引,这是关键,因此您会看到真正的性能提升。

【讨论】:

以上是关于带有索引字段的 MongoDB 正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

如何使用正则表达式创建索引显示所有字段

mongodb 正则表达式查询性能问题

MongoDB 索引和非索引性能

MongoDB OR与正则表达式不使用复合索引

MongoDB发现正则表达式很慢

MongoDB发现正则表达式很慢