我在项目中遇到一个MongoDB的问题,好多天了还是没能得到解决,希望得到大牛的指点。
具体问题是:长时间不访问数据库的情况下,第一次查询数据库所需的时间很长,但是之后的查询就会很快。
具体情况:
①整个数据库大小大概在1.9TB左右;
②我查询的collection的数据大致为700万条;
③我查询一次得到的数据为23万条左右;
④服务器内存为120GB;
⑤已按照查询条件建立了索引,索引数据大小为600MB左右;
⑥第一次查询所用时间20s左右,之后的查询在1s以内。
目前考虑的原因:
由于MongoDB不负责内存的管理,所以,当长时间未访问数据库时,内存中的数据即为冷数据,操作系统的内存管理程序就会将这部分冷数据释放,导致下次查询时,需要重新加载数据到内存,所以比较费时。目前,不能够确定是加载索引比较费时,还是加载数据比较费时。MongoDB虽然提供了touch命令(该命令能够指定将某个collection的索引数据或者用户数据加载到内存中),但是我使用的是WiredTiger存储引擎,该命令不支持该存储引擎。
需要得到的帮助:
①是不是以上原因导致的该问题?
②如果是该原因导致的,如何确定是加载索引费时还是加载数据费时?
③有什么比较好的解决方案么?
注:由于该collection最大会达到25GB左右,而且整个数据库还有其他很多collection,所以将该collection的所有数据存储到内存是不可取的。如果能够确认是加载索引费时的话,倒是可以考虑定期将索引加载到内存,但是对于WiredTiger存储引擎,没有支持该功能的方法,这又是一个问题。
phpcn_u15822017-05-02 09:28:08
您说的这个问题是和working set相关联。
1、什么是working set?
MongoDB的内存管理中一个重要的概念。在内存管理中尽量将业务经常访问的数据集和相关的索引放置在内存中。
2、怎么将working set放置在内存中呢?
在您的表述中,其实是一个需要将working set提前预热放置在内存中(Preload or Preheating)。具体怎么做?您提到了touch(MMAP引擎),那么在后续的版本(WT引擎)中如何实现呢?
如果是关系型数据库,经常会用到的办法是select *,很多时候做性能测试,为达到好的效果,都会事先运行一批次Select语句预热内存。
在MongoDB中,可以考虑:
1)如果业务查询中可以直接使用到covered index来查询的,或者说需要预热index的时候:
db.collection.find({}, {"_id" : 0, "field_a" : 1, "field_b" : 1}).hint({"field_a" : 1, "field_b" : 1}).explain()
2)当需要预热working set时,前提是您知道你的collection中哪些数据是经常需要被访问的,通常是某个时间段,然后将这个时间段的collection,使用上面相同的方法来预热。
不同之处是:预热index是将这个index都预热了,所以查询条件是{},鹅而,预热working set,只是预热collection中某一部分数据,所以这个查询条件可能是和时间范围相关的条件。
供参考。
Love MongoDB!Have fun!
MongoDB中文社区深圳用户大会
这个周六,大家约起
详情请入