MongoDB查询未使用索引

4

我在MongoDB集合上设置了一个复合索引,但无论我如何具体地定位前缀,查询都无法使用它。

索引的创建方式:

db.collection.createIndex({"insert_time":-1,"name":"text"},{background: true})

索引规范输出:

db.collection.getIndexes()
[
{
    "v" : 2,
    "key" : {
        "_id" : 1
    },
    "name" : "_id_",
    "ns" : "db.collection"
},
{
    "v" : 2,
    "key" : {
        "insert_time" : -1,
        "_fts" : "text",
        "_ftsx" : 1
    },
    "name" : "insert_time_-1_name_text",
    "ns" : "db.collection",
    "background" : true,
    "weights" : {
        "name" : 1
    },
    "default_language" : "english",
    "language_override" : "language",
    "textIndexVersion" : 3
}
]

但是,即使是在最简单的insert_time查询中,explain()也显示出获胜的计划是执行COLLSCAN,而不使用任何索引:

db.collection.find({"insert_time": ISODate("2018-08- 
05T19:00:00Z")}).explain()
{
"queryPlanner" : {
    "plannerVersion" : 1,
    "namespace" : "db.collection",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "insert_time" : {
            "$eq" : ISODate("2018-08-05T19:00:00Z")
        }
    },
    "winningPlan" : {
        "stage" : "COLLSCAN",
        "filter" : {
            "insert_time" : {
                "$eq" : ISODate("2018-08-05T19:00:00Z")
            }
        },
        "direction" : "forward"
    },
    "rejectedPlans" : [ ]
},
"serverInfo" : {
    "host" : "foo",
    "port" : 0000,
    "version" : "3.4.10",
    "gitVersion" : "078f28920cb24de0dd479b5ea6c66c644f6326e9"
},
"ok" : 1
}

尽管索引被指定为“复合索引”,但我理解应该可以通过“前缀”进行搜索,这种情况下是insert_time。你有任何想法为什么Mongo不使用我的索引吗?
2个回答

5

text索引默认情况下是稀疏的

索引中的非文本索引字段没有引用text索引中的文档(参考)。

对于包含文本索引键以及其他类型的键的复合索引,仅文本索引字段确定索引是否引用文档。其他键不决定索引是否引用文档。

=>当使用无文本索引字段的前缀索引时,结果可能不完整

关于这种情况(稀疏索引和不完整的结果),MongoDB声明:

如果稀疏索引会导致查询和排序操作的结果集不完整,则MongoDB不会使用该索引,除非明确指定了提示()的索引。

如果使用hint('yourTextIndexName'),则使用索引。

因此,OP的情况是一种预期行为,但文档记录不太充分。


1
这是正确的答案。问题似乎也是一个重复的问题:https://dev59.com/W6Pia4cB1Zd3GeqPth0G#44894103 - Adam Harrison

0

这感觉像是一个 bug。

我能够在我的数据集上复现您看到的行为,使用 MongoDB 3.6.7。我在涉及的索引中加入了提示,并且查询规划器无法绑定前缀字段(我正在对 year 进行直接匹配):

"indexBounds" : {
                    "year" : [
                        "[MinKey, MaxKey]"
                    ],
                    "_fts" : [
                        "[MinKey, MaxKey]"
                    ],
                    "_ftsx" : [
                        "[MinKey, MaxKey]"
                    ]
                },

复合文本索引的文档中没有任何声明表明无法使用文本索引的前缀部分。索引前缀的文档中也没有关于限制的语言。

编辑:

我创建了一个服务器工单来报告此行为并尝试获取更多信息,以确定这是否是预期行为还是错误。


确实没有太多关于复合文本索引如何工作的解释,但我的直觉是每个文本标记仍然是一个索引条目。这意味着您不能仅查询“insert_time”,因为这将无法找到文本字段完全为空的文档。前缀列只有在文本搜索的基础上有效地限制时才有用。 - Thilo
也许添加类似于 AND text HAS ANY TOKENS 的内容可以使其工作?但我不知道如何编写。 - Thilo
1
我也有这样的感觉,即文本索引只能用于执行文本搜索。虽然我本来希望这在复合文本索引下有所记录。此外,这个语句似乎几乎(但并不是)暗示它们可以用于非文本搜索:如果复合文本索引包括在文本索引键之前的键,则要执行 $text 搜索,查询谓词必须包括前面键的等值匹配条件。(来自上面的复合文本索引链接)。 - Adam Harrison
1
请看我的编辑;我创建了一个服务器票证,试图确认这是否是预期的。 - Adam Harrison
请将那张票据与此处进行交叉链接。 - Thilo
1
我创建的工单是https://jira.mongodb.org/browse/SERVER-37059,但我认为Mạnh Quyết Nguyễn找到了一些文档来确认这是预期行为。 - Adam Harrison

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接