千家信息网

由正则表示式匹配($regex)引起的一次mongo数据库c

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,某一天,监控到mongo数据库cpu使用率高了很多,查了一下,发现是下面这种语句引起的:db.example_collection.find({ "idField" : { "$regex" : "1
千家信息网最后更新 2026年10月31日由正则表示式匹配($regex)引起的一次mongo数据库c

某一天,监控到mongo数据库cpu使用率高了很多,查了一下,发现是下面这种语句引起的:

db.example_collection.find({ "idField" : { "$regex" : "123456789012345678"} , "dateField" : { "$regex" : "2019/10/10"}})


通常,遇到这种情况,我第一反应是缺少相关字段的索引,导致每执行一次这种语句都会全表扫描一次。


但是我用explain( )语句分析了下,发现上面所涉及的两个字段idField、dateField是有索引的,并且该语句也是有使用到索引的。如下为explain( )的结果:

mgset-11111111:PRIMARY> db.example_collection.find({ "idField" : { "$regex" : "123456789012345678"} , "dateField" : { "$regex" : "2019/10/10"}}).explain("queryPlanner")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "example_db.example_collection",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"idField" : {
"$regex" : "123456789012345678"
}
},
{
"dateField" : {
"$regex" : "2019/10/10"
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"filter" : {
"$and" : [
{
"idField" : {
"$regex" : "123456789012345678"
}
},
{
"dateField" : {
"$regex" : "2019/10/10"
}
}
]
},
"keyPattern" : {
"idField" : 1,
"dateField" : 1
},
"indexName" : "idField_1_dateField_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"idField" : [ ],
"dateField" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"idField" : [
"[\"\", {})",
"[/123456789012345678/, /123456789012345678/]"
],
"dateField" : [
"[\"\", {})",
"[/2019/10/10/, /2019/10/10/]"
]
}
}
},
"rejectedPlans" : [ ]
},
"ok" : 1
}


查看mongo的日志发现,这种语句执行一次就要800~900ms,的确是比较慢。除非数据库cpu核数很多,要不然只要这种语句每秒并发稍微高一点,cpu很快就被占满了。


之后搜索了下,发现有可能是正则表达式的问题。原来,虽然该语句的确是使用了索引,但是explain( )语句的输出中还有一个字段"indexBounds",表示执行该语句时所需扫描的索引范围。说实话,上面那个输出中,我始终没看明白它那个索引范围。上面的语句对idField、dateField这两个字段都进行了普通的正则表达式匹配,我猜测它应该是扫描了整个索引树,所以导致索引并未实际提升该语句的查询效率。


我看了下数据库里面的数据,发现idField、dateField这两个字段完全没有必要进行正则匹配,进行普通的文本匹配就行。将正则匹配操作$regex去掉之后,再分析一下,结果是这样的:

mgset-11111111:PRIMARY> db.example_collection.find({ "idField" : "123456789012345678", "dateField" : "2019/10/10"}).explain("queryPlanner")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "example_db.example_collection",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"idField" : {
"$eq" : "123456789012345678"
}
},
{
"dateField" : {
"$eq" : "2019/10/10"
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"idField" : 1,
"dateField" : 1
},
"indexName" : "idField_1_dateField_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"idField" : [ ],
"dateField" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"idField" : [
"[\"123456789012345678\", \"123456789012345678\"]"
],
"dateField" : [
"[\"2019/10/10\", \"2019/10/10\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"ok" : 1
}


可以看到,仍然使用到了索引,并且索引扫描范围是仅限于一个值的。


后来跟开发人员确认了下,该语句确实没必要使用正则匹配,就让他把正则匹配去掉了。之后就没有再出现问题了,mongo慢日志中也未再出现该语句。

语句 索引 正则 字段 数据 两个 范围 数据库 普通 必要 日志 结果 表达式 问题 面的 分析 输出 说实话 人员 使用率 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 高科技互联网 广州百单互联网科技有限公司 互联网属科技 互联网通讯科技 北京互联网科技公司 深圳互联网络科技有限公司 礼当家互联网科技 互联网科技ppt模板 互联网科技有限公司 翻译 滨湖区互联网智能科技产品供应 互联网科技与管理 互联网在线教育科技创业 互联网公司高科技产品 互联网企业科技类企业如何做账 广州燕处互联网科技有限公司 互联网科技企业商标注意事项 互联网科技手抄报图片 互联网科技的前景 深圳互联网科技园地址 青岛易易互联网科技 互联网科技公司简介 互联网科技公司经营范围 互联网科技的未来发展 撒么互联网科技公司 深圳卡尔迅互联网科技有限公司怎么样 受益于互联网科技的高速发展 移动互联网年度科技创新 沐思想互联网科技有限公司 锡山区互联网智能科技产品供应 恒生科技互联网指数十大成分股
0