MongoDB$或对自身的查询速度要快得多

MongoDB$或对自身的查询速度要快得多,mongodb,mongodb-query,Mongodb,Mongodb Query,我有一个mongo实例,集合中有16m个文档。我写了一个查询来搜索一个(索引的)字段,我得到了一些奇怪的结果,我无法解释 如果我直接执行查询,如: find({ "$and" : [ { "ipAddr" : { "$regex" : "^01:172"}} , { "active" : true}]}).limit(100).sort({ "_id" : 1}) 甚至在查询中添加一个毫无意义的$or: find({ "$and" : [ { "$or" : [ { "ipAddr" : {

我有一个mongo实例,集合中有16m个文档。我写了一个查询来搜索一个(索引的)字段,我得到了一些奇怪的结果,我无法解释

如果我直接执行查询,如:

find({ "$and" : [ { "ipAddr" : { "$regex" : "^01:172"}} , { "active" : true}]}).limit(100).sort({ "_id" : 1})
甚至在查询中添加一个毫无意义的$or:

find({ "$and" : [ { "$or" : [ { "ipAddr" : { "$regex" : "^01:172"}}]} , { "active" : true}]}).limit(100).sort({ "_id" : 1})
它回来了 在71673ms内获取了3条记录

但是,如果我对其本身使用$or,如:

find({ "$and" : [ { "$or" : [ { "ipAddr" : { "$regex" : "^01:172"}} , { "ipAddr" : { "$regex" : "^01:172"}}]} , { "active" : true}]}).limit(100).sort({ "_id" : 1})
它返回: 在4ms内获取了3条记录

所以性能差异很大。通过检查查询的explain(),我无法确定为什么存在如此大的性能差异。有人能解释一下我遗漏了什么,或者mongo在这两者之间做了什么不同吗

Explain()在单个$or上,耗时>60000毫秒

find({ "$and" : [ { "$or" : [ { "ipAddr" : { "$regex" : "^01:172"}}]} , { "active" : true}]}).limit(100).sort({ "_id" : 1}).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "CLS-TEST.Leases",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "active" : {
                        "$eq" : true
                    }
                },
                {
                    "ipAddr" : /^01:172/
                }
            ]
        },
        "winningPlan" : {
            "stage" : "SORT",
            "sortPattern" : {
                "_id" : 1
            },
            "limitAmount" : 100,
            "inputStage" : {
                "stage" : "SORT_KEY_GENERATOR",
                "inputStage" : {
                    "stage" : "FETCH",
                    "filter" : {
                        "active" : {
                            "$eq" : true
                        }
                    },
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "keyPattern" : {
                            "ipAddr" : 1
                        },
                        "indexName" : "ipAddr_1",
                        "isMultiKey" : false,
                        "isUnique" : false,
                        "isSparse" : false,
                        "isPartial" : false,
                        "indexVersion" : 1,
                        "direction" : "forward",
                        "indexBounds" : {
                            "ipAddr" : [
                                "[\"01:172\", \"01:173\")",
                                "[/^01:172/, /^01:172/]"
                            ]
                        }
                    }
                }
            }
        },
        "rejectedPlans" : [
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "ipAddr" : /^01:172/
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "sessionId" : 1,
                                "updateTime" : 1
                            },
                            "indexName" : "active_1_sessionId_1_updateTime_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "sessionId" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "updateTime" : [
                                    "[MinKey, MaxKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "ipAddr" : /^01:172/
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "clientId" : 1,
                                "startTime" : -1,
                                "_id" : -1
                            },
                            "indexName" : "active_1_clientId_1_startTime_-1__id_-1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "clientId" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "startTime" : [
                                    "[MaxKey, MinKey]"
                                ],
                                "_id" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "ipAddr" : 1,
                                "startTime" : -1,
                                "_id" : -1
                            },
                            "indexName" : "active_1_ipAddr_1_startTime_-1__id_-1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "ipAddr" : [
                                    "[\"01:172\", \"01:173\")",
                                    "[/^01:172/, /^01:172/]"
                                ],
                                "startTime" : [
                                    "[MaxKey, MinKey]"
                                ],
                                "_id" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "ipAddr" : /^01:172/
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "macAddress" : 1,
                                "startTime" : -1,
                                "_id" : -1
                            },
                            "indexName" : "active_1_macAddress_1_startTime_-1__id_-1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "macAddress" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "startTime" : [
                                    "[MaxKey, MinKey]"
                                ],
                                "_id" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "ipAddr" : /^01:172/
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "remoteId" : 1,
                                "startTime" : -1,
                                "_id" : -1
                            },
                            "indexName" : "active_1_remoteId_1_startTime_-1__id_-1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "remoteId" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "startTime" : [
                                    "[MaxKey, MinKey]"
                                ],
                                "_id" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "LIMIT",
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "FETCH",
                    "filter" : {
                        "$and" : [
                            {
                                "active" : {
                                    "$eq" : true
                                }
                            },
                            {
                                "ipAddr" : /^01:172/
                            }
                        ]
                    },
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "keyPattern" : {
                            "_id" : 1
                        },
                        "indexName" : "_id_",
                        "isMultiKey" : false,
                        "isUnique" : true,
                        "isSparse" : false,
                        "isPartial" : false,
                        "indexVersion" : 1,
                        "direction" : "forward",
                        "indexBounds" : {
                            "_id" : [
                                "[MinKey, MaxKey]"
                            ]
                        }
                    }
                }
            }
        ]
    },
    "serverInfo" : {
        "host" : "",
        "port" : 27017,
        "version" : "3.2.3",
        "gitVersion" : "b326ba837cf6f49d65c2f85e1b70f6f31ece7937"
    },
    "ok" : 1
}

Explain()在$上或对其本身进行解释,这需要您可能会注意到,没有任何索引选择包括
“active”
“ipAddr”
的组合,这将是此处定义的有用索引

简而言之,“较慢”查询只使用
“ipAddr”
的索引,因此需要更多的工作才能“过滤”出
{“active”:true}
条目

显然,当其他索引选择使用带有这些边界的
“active”
键时,传递给regex模式上后续过滤器的结果较少。这里似乎有很多索引,但没有一个真正适合查询

我将为您提供至少在任一查询上运行“explain”输出的道具,但如果仔细观察,您会发现“slow”查询“错误地”选择了
“ipAddr”
索引,认为它是最佳的。可能不是,但乐观主义者考虑使用“锚定”正则表达式是一个合理的假设

$或
中只有“一”个参数时,它就不会这样做了。“两个”参数可以实现这一点,而优化者通过查找在其他查询条件之前的索引(
“active”
值)进行另一个“猜测”

这是有道理的,因为它现在正在运行“两个”查询,从中它将“相交”结果,因此
$或
语句之外的任何条件都将是最佳选择索引的逻辑选择

由于从这些结果返回的结果可能较小,因此“筛选”出正则表达式匹配比查看所有正则表达式结果并筛选出“活动”值更快

因此,为该查询定义的“最佳”索引为:

.createIndex({“活动”:1,“ipAddr”:1})

然后,两个查询的结果都是一致的,当然前提是优化者不会被其他索引所迷惑,而是选择了那个索引。要强制选择索引,请使用

您可能会注意到,所有索引选择都不包括
“active”
“ipAddr”
的组合,这将是此处要定义的有用索引

简而言之,“较慢”查询只使用
“ipAddr”
的索引,因此需要更多的工作才能“过滤”出
{“active”:true}
条目

显然,当其他索引选择使用带有这些边界的
“active”
键时,传递给regex模式上后续过滤器的结果较少。这里似乎有很多索引,但没有一个真正适合查询

我将为您提供至少在任一查询上运行“explain”输出的道具,但如果仔细观察,您会发现“slow”查询“错误地”选择了
“ipAddr”
索引,认为它是最佳的。可能不是,但乐观主义者考虑使用“锚定”正则表达式是一个合理的假设

$或
中只有“一”个参数时,它就不会这样做了。“两个”参数可以实现这一点,而优化者通过查找在其他查询条件之前的索引(
“active”
值)进行另一个“猜测”

这是有道理的,因为它现在正在运行“两个”查询,从中它将“相交”结果,因此
$或
语句之外的任何条件都将是最佳选择索引的逻辑选择

由于从这些结果返回的结果可能较小,因此“筛选”出正则表达式匹配比查看所有正则表达式结果并筛选出“活动”值更快

因此,为该查询定义的“最佳”索引为:

.createIndex({“活动”:1,“ipAddr”:1})

然后,两个查询的结果都是一致的,当然前提是优化者不会被其他索引所迷惑,而是选择了那个索引。要强制选择索引,请使用

感谢详细的响应和指向“索引交点”的指针。我希望避免创建额外的索引,因为其他索引可以减少维护开销,但这可能是必需的。@caverman关于索引的数量,您可能希望仔细查看所有查询模式(并解释输出),然后决定是否真的需要它们。最好只使用复合索引,其中索引键被“最佳地”使用,因此在使用最常见的组合和它们可能过滤的结果之前。这里的教训主要是,
“active”
是减少可能结果的实际值,对于此查询,至少该值将作为索引中的前一项发挥最大的作用。感谢详细的响应和指向“索引交叉点”的指针。我希望避免创建额外的索引,因为其他索引可以减少维护开销,但这可能是必需的。@caverman关于索引的数量,您可能需要
find({ "$and" : [ { "$or" : [ { "ipAddr" : { "$regex" : "^01:172"}} , { "ipAddr" : { "$regex" : "^01:172"}}]} , { "active" : true}]}).limit(100).sort({ "_id" : 1}).explain()
{
    "queryPlanner" : {
        "plannerVersion" : 1,
        "namespace" : "CLS-TEST.Leases",
        "indexFilterSet" : false,
        "parsedQuery" : {
            "$and" : [
                {
                    "$or" : [
                        {
                            "ipAddr" : /^01:172/
                        },
                        {
                            "ipAddr" : /^01:172/
                        }
                    ]
                },
                {
                    "active" : {
                        "$eq" : true
                    }
                }
            ]
        },
        "winningPlan" : {
            "stage" : "SORT",
            "sortPattern" : {
                "_id" : 1
            },
            "limitAmount" : 100,
            "inputStage" : {
                "stage" : "SORT_KEY_GENERATOR",
                "inputStage" : {
                    "stage" : "FETCH",
                    "filter" : {
                        "active" : {
                            "$eq" : true
                        }
                    },
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "keyPattern" : {
                            "ipAddr" : 1
                        },
                        "indexName" : "ipAddr_1",
                        "isMultiKey" : false,
                        "isUnique" : false,
                        "isSparse" : false,
                        "isPartial" : false,
                        "indexVersion" : 1,
                        "direction" : "forward",
                        "indexBounds" : {
                            "ipAddr" : [
                                "[\"01:172\", \"01:173\")",
                                "[/^01:172/, /^01:172/]"
                            ]
                        }
                    }
                }
            }
        },
        "rejectedPlans" : [
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$or" : [
                                {
                                    "ipAddr" : /^01:172/
                                },
                                {
                                    "ipAddr" : /^01:172/
                                }
                            ]
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "sessionId" : 1,
                                "updateTime" : 1
                            },
                            "indexName" : "active_1_sessionId_1_updateTime_1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "sessionId" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "updateTime" : [
                                    "[MinKey, MaxKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$or" : [
                                {
                                    "ipAddr" : /^01:172/
                                },
                                {
                                    "ipAddr" : /^01:172/
                                }
                            ]
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "clientId" : 1,
                                "startTime" : -1,
                                "_id" : -1
                            },
                            "indexName" : "active_1_clientId_1_startTime_-1__id_-1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "clientId" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "startTime" : [
                                    "[MaxKey, MinKey]"
                                ],
                                "_id" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$or" : [
                                {
                                    "ipAddr" : /^01:172/
                                },
                                {
                                    "ipAddr" : /^01:172/
                                }
                            ]
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "ipAddr" : 1,
                                "startTime" : -1,
                                "_id" : -1
                            },
                            "indexName" : "active_1_ipAddr_1_startTime_-1__id_-1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "ipAddr" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "startTime" : [
                                    "[MaxKey, MinKey]"
                                ],
                                "_id" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$or" : [
                                {
                                    "ipAddr" : /^01:172/
                                },
                                {
                                    "ipAddr" : /^01:172/
                                }
                            ]
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "macAddress" : 1,
                                "startTime" : -1,
                                "_id" : -1
                            },
                            "indexName" : "active_1_macAddress_1_startTime_-1__id_-1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "macAddress" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "startTime" : [
                                    "[MaxKey, MinKey]"
                                ],
                                "_id" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "SORT",
                "sortPattern" : {
                    "_id" : 1
                },
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "SORT_KEY_GENERATOR",
                    "inputStage" : {
                        "stage" : "FETCH",
                        "filter" : {
                            "$or" : [
                                {
                                    "ipAddr" : /^01:172/
                                },
                                {
                                    "ipAddr" : /^01:172/
                                }
                            ]
                        },
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "active" : 1,
                                "remoteId" : 1,
                                "startTime" : -1,
                                "_id" : -1
                            },
                            "indexName" : "active_1_remoteId_1_startTime_-1__id_-1",
                            "isMultiKey" : false,
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 1,
                            "direction" : "forward",
                            "indexBounds" : {
                                "active" : [
                                    "[true, true]"
                                ],
                                "remoteId" : [
                                    "[MinKey, MaxKey]"
                                ],
                                "startTime" : [
                                    "[MaxKey, MinKey]"
                                ],
                                "_id" : [
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    }
                }
            },
            {
                "stage" : "LIMIT",
                "limitAmount" : 100,
                "inputStage" : {
                    "stage" : "FETCH",
                    "filter" : {
                        "$and" : [
                            {
                                "$or" : [
                                    {
                                        "ipAddr" : /^01:172/
                                    },
                                    {
                                        "ipAddr" : /^01:172/
                                    }
                                ]
                            },
                            {
                                "active" : {
                                    "$eq" : true
                                }
                            }
                        ]
                    },
                    "inputStage" : {
                        "stage" : "IXSCAN",
                        "keyPattern" : {
                            "_id" : 1
                        },
                        "indexName" : "_id_",
                        "isMultiKey" : false,
                        "isUnique" : true,
                        "isSparse" : false,
                        "isPartial" : false,
                        "indexVersion" : 1,
                        "direction" : "forward",
                        "indexBounds" : {
                            "_id" : [
                                "[MinKey, MaxKey]"
                            ]
                        }
                    }
                }
            }
        ]
    },
    "serverInfo" : {
        "host" : "",
        "port" : 27017,
        "version" : "3.2.3",
        "gitVersion" : "b326ba837cf6f49d65c2f85e1b70f6f31ece7937"
    },
    "ok" : 1
}