向MongoDB查询添加过滤器会增加count()所需的时间

时间:2018-02-23 14:03:56

标签: mongodb mongodb-query

我有一个名为listings的集合,其中包含超过500万个文档和索引(仅相关),其中包含键:
{"_id": 1}
{"dated": 1}
{"causelist_type": 1}

我正在尝试运行查询

db.listings.count({
    dated: {
        $in: [ISODate("2018-02-17T00:00:00Z"), ISODate("2018-02-16T00:00:00Z"),ISODate("2018-02-10T00:00:00Z")]
    },
    causelist_type: {$ne: -1}
})

需要130秒。 (通过前缀和附加print(new Date())命令

来记录)

但是如果删除过滤器causelist_type: {$ne: -1},查询几乎会立即运行(~1s)。

带有explain().queryPlanner子句的查询的

causelist_type

{
    "plannerVersion" : 1,
    "namespace" : "kl.listings",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "$and" : [
            {
                "dated" : {
                    "$in" : [
                        ISODate("2018-02-10T00:00:00Z"),
                        ISODate("2018-02-16T00:00:00Z"),
                        ISODate("2018-02-17T00:00:00Z")
                    ]
                }
            },
            {
                "$nor" : [{
                    "causelist_type" : {
                        "$eq" : -1
                    }
                }]
            }
        ]
    },
    "winningPlan" : {
        "stage" : "FETCH",
        "filter" : {
            "$nor" : [{
                "causelist_type" : {
                    "$eq" : -1
                }
            }]
        },
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                    "dated" : 1
            },
            "indexName" : "dated_1",
            "isMultiKey" : false,
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 1,
            "direction" : "forward",
            "indexBounds" : {
                "dated" : [
                    "[new Date(1518220800000), new Date(1518220800000)]",
                    "[new Date(1518739200000), new Date(1518739200000)]",
                    "[new Date(1518825600000), new Date(1518825600000)]"
                ]
            }
        }
    },
    "rejectedPlans" : [{
        "stage" : "FETCH",
        "filter" : {
                "dated" : {
                        "$in" : [
                                ISODate("2018-02-10T00:00:00Z"),
                                ISODate("2018-02-16T00:00:00Z"),
                                ISODate("2018-02-17T00:00:00Z")
                        ]
                }
        },
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                    "causelist_type" : 1
            },
            "indexName" : "causelist_type_1",
            "isMultiKey" : false,
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 1,
            "direction" : "forward",
            "indexBounds" : {
                "causelist_type" : [
                    "[MinKey, -1.0)",
                    "(-1.0, MaxKey]"
                ]
            }
        }
    }]
}

explain().queryPlanner查询没有 causelist_type子句:

{
    "plannerVersion" : 1,
    "namespace" : "kl.listings",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "dated" : {
            "$in" : [
                ISODate("2018-02-10T00:00:00Z"),
                ISODate("2018-02-16T00:00:00Z"),
                ISODate("2018-02-17T00:00:00Z")
            ]
        }
    },
    "winningPlan" : {
        "stage" : "COUNT",
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                "dated" : 1
            },
            "indexName" : "dated_1",
            "isMultiKey" : false,
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 1,
            "direction" : "forward",
            "indexBounds" : {
            "dated" : [
                    "[new Date(1518220800000), new Date(1518220800000)]",
                    "[new Date(1518739200000), new Date(1518739200000)]",
                    "[new Date(1518825600000), new Date(1518825600000)]"
                ]
            }
        }
    },
    "rejectedPlans" : [ ]
}

我正在使用MongoDB 3.6.2。

我不明白的是如何添加'过滤器'在使用和不使用'过滤器的查询中使用相同索引时,会大大增加查询时间。 如果您需要更多信息,请与我们联系。

编辑:
我还尝试将causelist_type子句修改为causelist_type: {$eq: -1},查询立即运行。请解释一下。

编辑2: 对explain().queryPlanner子句的查询causelist_type: {$eq: -1}

{
    "plannerVersion" : 1,
    "namespace" : "kl.listings",
    "indexFilterSet" : false,
    "parsedQuery" : {
        "$and" : [{
            "causelist_type" : {
                "$eq" : -1
            }
        },
        {
            "dated" : {
                "$in" : [
                    ISODate("2018-02-10T00:00:00Z"),
                    ISODate("2018-02-16T00:00:00Z"),
                    ISODate("2018-02-17T00:00:00Z")
                ]
            }
        }]
    },
    "winningPlan" : {
        "stage" : "FETCH",
        "filter" : {
            "causelist_type" : {
                "$eq" : -1
            }
        },
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                    "dated" : 1
            },
            "indexName" : "dated_1",
            "isMultiKey" : false,
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 1,
            "direction" : "forward",
            "indexBounds" : {
                "dated" : [
                    "[new Date(1518220800000), new Date(1518220800000)]",
                    "[new Date(1518739200000), new Date(1518739200000)]",
                    "[new Date(1518825600000), new Date(1518825600000)]"
                ]
            }
        }
    },
    "rejectedPlans" : [{
        "stage" : "FETCH",
        "filter" : {
            "dated" : {
                "$in" : [
                    ISODate("2018-02-10T00:00:00Z"),
                    ISODate("2018-02-16T00:00:00Z"),
                    ISODate("2018-02-17T00:00:00Z")
                ]
            }
        },
        "inputStage" : {
            "stage" : "IXSCAN",
            "keyPattern" : {
                "causelist_type" : 1
            },
            "indexName" : "causelist_type_1",
            "isMultiKey" : false,
            "isUnique" : false,
            "isSparse" : false,
            "isPartial" : false,
            "indexVersion" : 1,
            "direction" : "forward",
            "indexBounds" : {
                "causelist_type" : [
                    "[-1.0, -1.0]"
                ]
            }
        }
    }]
}

当我将causelist_type子句更改为causelist_type: {$nin: [-1, -2]}时,它并使用与causelist_type: {$eq: -1}相同的索引和输入阶段,只是一个不同的过滤器。

他们都没有使用索引交集,因为explain results documentation表示在使用索引交集的情况下我们应该"stage" : "AND_SORTED"

1 个答案:

答案 0 :(得分:1)

如果查询中没有causelist_type字词,则dated上的索引完全涵盖了计数查询,这使得它非常快。

请注意此案例的获胜计划中的"stage" : "COUNT"

causelist_type添加到查询中需要从磁盘读取满足查询dated部分的每个文档,以便可以检查其causelist_type值以查看它是否&# 39; s $ne: -1

请注意此案例的获胜计划中的"stage" : "FETCH"

至于为什么索引交集在这里与causelist_type索引一起使用时,可能是因为你正在使用$ne查询,这使得索引更多效率低于匹配(正如您在使用$eq进行测试时发现的那样)。