背景
事件列表分页查询时,报如下错:
说明:事件表中,如果事件如果聚合了很多告警,那这些事件的大小就会很大
问题分析
问题说明
MongoDB的 sort 操作是把数据拿到内存中再进行排序的,为了节约内存,默认给 sort 操作限制了最大内存为32M(mongo4.3以上版本是100M),当数据量超过限制后,就会抛异常。
如果排序或者查询时,命中了排序字段,那排序的时候,只需要将排序字段拉到内存中进行排序,如果未命中索引,则会将查询出来的所有文档拉到内存中进行排序。
代码分析
先来看下报错那一行的代码:
这里的排序,使用的是 lastDetectionTime 字段,来看下事件表建立的索引有哪些:
通过代码可以看到,查询条件只有主键ID列表,所以排序的时候,是不会走任何索引的。
解决方案
方案一:修改排序限制(不推荐)
将mongo排序限制改为100M。执行如下命令:
/usr/local/qingteng/mongodb/bin/mongo --host localhost --port 27017 -u qingteng -p fMElKUz36MY00ceg --authenticationDatabase admin use amdin; db.runCommand({ setParameter: 1, "internalQueryExecMaxBlockingSortBytes": 104857600 });
执行效果:
方案二:排序字段创建索引(不推荐)
由于现在的查询条件不会命中组合索引 comId_lastDetectionTime,那只需要改下这个索引就可以命中。
删除组合索引comId_lastDetectionTime,新建组合索引lastDetectionTime_comId,命令:
db.ids_incident.createIndex({lastDetectionTime:-1, comId:1},{name:"lastDetectionTime_comId"})
方案三:修改查询条件
既然现有的查询条件不会命中组合索引 comId_lastDetectionTime,那就改下查询条件,让查询字段带上该组合索引。修改后的代码如下:
说明:最上面的IncidentQuery中是一定会包含comId、startTime、endTime的