MongoDB 索引失效问题排查

阅读时长 10 分钟读完

问题概述

在 MongoDB 数据库中,索引的使用能够大幅提升查询效率。然而,有时候我们会发现索引并不起作用,导致查询性能下降。此时,我们需要进行索引失效问题的排查和定位。

常见原因

如何才能排查出索引失效的原因呢?下面是几个常见的原因:

1. 索引字段类型不匹配

如果查询语句中的字段类型和索引中的字段类型不一致,那么索引将无法生效。例如,如果索引是基于字符串类型的字段建立的,而查询语句传递的是数字类型,那么查询语句就无法使用索引。

2. 非前缀匹配

如果索引的字段是一个复合字段,那么查询语句中必须使用该字段的前缀匹配模式才能使用索引。例如,我们有一个复合索引 {a: 1, b: 1} ,那么查询语句中必须有类似于 {a: value} 或者 {a: value, b: value} 的模式才能使用该索引。

3. 模糊查询

模糊查询(比如使用正则表达式或 $where 操作符进行查询)也可能导致索引失效。这是因为模糊查询无法利用索引的 B 树结构,会导致 MongoDB 引擎必须扫描整个集合,从而大幅降低查询性能。

4. 子句次序问题

查询语句中子句次序的不同也可能导致索引失效。例如,如果查询语句的 $or 运算符在前面,那么即使存在 $and 运算符,查询也无法使用索引。

排查流程

了解了一些常见原因后,下面我们来介绍一下排查索引失效问题的基本流程:

1. 使用 explain 进行查询分析

explain 命令可以分析出查询语句的执行计划和优化方式,从而帮助我们判断索引是否生效。例如,我们可以使用下面的命令进行查询分析:

其中,executionStats 参数可以让 explain 命令显示查询执行的详细信息。

2. 检查索引是否被正确创建

我们需要 inspect 索引本身以确定它们是否正确创建。我们可以使用 db.collection.getIndexes() 命令来查看索引的详细信息,确认索引是否被正确创建。

3. 确定索引字段类型是否正确

我们需要检查查询语句中的字段类型是否与索引的字段类型匹配。如果不匹配,这可能会导致索引失效。

4. 确定是否存在非前缀匹配

我们需要确定查询语句中是否出现了非前缀匹配的情况。如果出现了非前缀匹配,索引将无法使用。

5. 确定是否存在模糊查询

我们需要确定查询语句中是否出现了模糊查询。如果存在模糊查询,那么即使存在索引,也无法提高查询性能。

6. 检查子句的次序是否正确

我们需要确认查询语句中的子句次序是否正确。如果次序不正确,将导致索引失效。

实例演示

下面提供一个实例演示来加深大家的理解。假设我们有一个 MongoDB 集合,其中的文档如下所示:

-- -------------------- ---- -------
-
    ------ -------------------------------------
    ------- -------
    ------ ---
    ---------- -
        ------- -----------
        --------- --------- ---- ------- -----
    -
-

现在,我们需要查询出居住在 Shanghai 的用户,并且年龄等于 18 。我们可以使用以下语句进行查询:

如果我们建立了基于 city 和 age 的联合索引,那么这个查询语句应该会比较快速。现在,我们可以使用 explain 命令来检查查询执行计划:

执行结果如下所示:

-- -------------------- ---- -------
-
    -------------- - -
        ---------------- - --
        ----------- - ------------
        ---------------- - ------
        ------------- - -
            ------ - -
                -
                    -------------- - -
                        ----- - ----------
                    -
                --
                -
                    ----- - -
                        ----- - --
                    -
                -
            -
        --
        ------------- - -
            ------- - --------
            -------- - -
                -------------- - -
                    ----- - ----------
                --
                ----- - -
                    ----- - --
                -
            --
            ------------ - -
                ------- - ---------
                ------------ - -
                    -------------- - --
                    ----- - -
                --
                ----------- - -----------
                ------------ - ------
                --------------- - -
                    -------------- - - --
                    ----- - - -
                --
                ---------- - ------
                ---------- - ------
                ----------- - ------
                -------------- - --
                ----------- - ----------
                ------------- - -
                    -------------- - -
                        --------------- --------------
                    --
                    ----- - -
                        ------- ------
                    -
                -
            -
        --
        --------------- - - -
    --
    ---------------- - -
        ------------------ - -----
        ----------- - --
        --------------------- - --
        ------------------- - --
        ------------------- - --
        ----------------- - -
            ------- - --------
            -------- - -
                -------------- - -
                    ----- - ----------
                --
                ----- - -
                    ----- - --
                -
            --
            ----------- - --
            ----------------------------- - --
            ------- - --
            ---------- - --
            ---------- - --
            ----------- - --
            ----------- - --
            -------------- - --
            ------- - --
            -------------- - --
            --------------- - --
            ------------ - -
                ------- - ---------
                ----------- - --
                ----------------------------- - --
                ------- - --
                ---------- - --
                ---------- - --
                ----------- - --
                ----------- - --
                -------------- - --
                ------- - --
                ------------ - -
                    -------------- - --
                    ----- - -
                --
                ----------- - -----------
                ------------ - ------
                --------------- - -
                    -------------- - - --
                    ----- - - -
                --
                ---------- - ------
                ---------- - ------
                ----------- - ------
                -------------- - --
                ----------- - ----------
                ------------- - -
                    -------------- - -
                        --------------- --------------
                    --
                    ----- - -
                        ------- ------
                    -
                --
                -------------- - --
                ------- - --
                ------------ - --
                ------------- - --
                ----------------- - -
            -
        --
        ------------------- - - -
    --
    ------------ - -
        ------ - ----------------
        ---
    --
    ---- - ---
-

执行结果中,我们可以看到 winningPlan 的结果,这项结果告诉我们这个查询语句的执行计划,也就是 MongoDB 引擎决定如何执行这个查询语句的方式。我们也可以查看执行时间,其中 executionTimeMillis 表示查询语句的执行时间。在本例中,执行时间为 0 毫秒。

从执行计划可以看到,这个查询语句使用了索引,并且花费了很短的时间来查询出命中的文档。

总结

在本文中,我们介绍了 MongoDB 索引失效问题的排查方法。我们首先介绍了常见的失效原因,然后提供了问题排查的基本流程。最后,我们通过实例演示加深了大家的理解。希望这篇文章对于大家排查 MongoDB 索引失效问题有所帮助。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/645f8927968c7c53b018b9a1

纠错
反馈