千家信息网

由正则表示式匹配($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安全错误 数据库的锁怎样保障安全 中智农互联网科技 河南云网互联网络科技有限公司 中国互联网科技工作委员会毛军 互联网科技行业发展 智能科技公司是互联网公司吗 互联网科技英文 深圳齐家互联网科技 科技创新互联网企业 时间互联网络科技 互联网巨头投资的硬核科技 荆州市昕露互联网络科技有限公司 苏州五指互联网络科技有限 湖南一路畅行互联网科技 互联网5g黑科技有哪些 2021互联网科技公司排名 半导体是互联网高科技吗 互联网与数字科技关系 互联网科技手机排行榜 陕西九四连强互联网科技有限公司 科技互联网经济论坛 互联网科技巨头监管 厦门中拓互联网络科技有限公司 互联网中国科技 火传媒上海互联网科技 互联网科技视频素材 互联网科技创新企业排名 温州喔噻互联网科技有限公司 洛阳昕诺飞互联网科技有限公司 互联网科技创新的路径 互联网科技融合创新
0