MongoDB的磁盘IO相关情况的解决方案有哪些
Admin 2022-07-27 群英技术资讯 258 次浏览
有点标题党的意思,不过下面三招确实比较实用,内容来自Conversocial公司的VP Colin Howe在London MongoDB用户组的一个分享。
申请:下面几点并非放四海皆准的法则,具体是否能够使用,还需要根据自己的应用场景和数据特点来决定。
我们知道MongoDB是一个文档数据库,其每一条记录都是一个JSON格式的文档。比如像下面的例子,每一天会生成一条这样的统计数据:
{ metric: "content_count", client: 5, value: 51, date: ISODate("2012-04-01 13:00") }
{ metric: "content_count", client: 5, value: 49, date: ISODate("2012-04-02 13:00") }
而如果采用组合式大文档的话,就可以这样将一个月的数据全部存到一条记录里:
{ metric: "content_count", client: 5, month: "2012-04", 1: 51, 2: 49, ... }
通过上面两种方式存储,预先一共存储大约7GB的数据(机器只有1.7GB的内存),测试读取一年信息,这二者的读性能差别很明显:
第一种: 1.6秒
第二种: 0.3秒
那么问题在哪里呢?
实际上原因是组合式的存储在读取数据的时候,可以读取更少的文档数量。而读取文档如果不能完全在内存中的话,其代价主要是被花在磁盘seek上,第一种存储方式在获取一年数据时,需要读取的文档数更多,所以磁盘seek的数量也越多。所以更慢。
实际上MongoDB的知名使用者foursquare就大量采用这种方式来提升读性能。见此
我们知道,MongoDB和传统数据库一样,都是采用B树作为索引的数据结构。对于树形的索引来说,保存热数据使用到的索引在存储上越集中,索引浪费掉的内存也越小。所以我们对比下面两种索引结构:
db.metrics.ensureIndex({ metric: 1, client: 1, date: 1})
与
db.metrics.ensureIndex({ date: 1, metric: 1, client: 1 })
采用这两种不同的结构,在插入性能上的差别也很明显。
当采用第一种结构时,数据量在2千万以下时,能够基本保持10k/s 的插入速度,而当数据量再增大,其插入速度就会慢慢降低到2.5k/s,当数据量再增大时,其性能可能会更低。
而采用第二种结构时,插入速度能够基本稳定在10k/s。
其原因是第二种结构将date字段放在了索引的第一位,这样在构建索引时,新数据更新索引时,不是在中间去更新的,只是在索引的尾巴处进行修改。那些插入时间过早的索引在后续的插入操作中几乎不需要进行修改。而第一种情况下,由于date字段不在最前面,所以其索引更新经常是发生在树结构的中间,导致索引结构会经常进行大规模的变化。
与第1点相同,这一点同样是考虑到传统机械硬盘的主要操作时间是花在磁盘seek操作上。
比如还是拿第1点中的例子来说,我们在插入数据的时候,预先将这一年的数据需要的空间都一次性插入。这能保证我们这一年12个月的数据是在一条记录中,是顺序存储在磁盘上的,那么在读取的时候,我们可能只需要一次对磁盘的顺序读操作就能够读到一年的数据,相比前面的12次读取来说,磁盘seek也只有一次。
db.metrics.insert([
{ metric: 'content_count', client: 3, date: '2012-01', 0: 0, 1: 0, 2: 0, ... }
{ .................................., date: '2012-02', ... })
{ .................................., date: '2012-03', ... })
{ .................................., date: '2012-04', ... })
{ .................................., date: '2012-05', ... })
{ .................................., date: '2012-06', ... })
{ .................................., date: '2012-07', ... })
{ .................................., date: '2012-08', ... })
{ .................................., date: '2012-09', ... })
{ .................................., date: '2012-10', ... })
{ .................................., date: '2012-11', ... })
{ .................................., date: '2012-12', ... })
])
结果:
如果不采用预留空间的方式,读取一年的记录需要62ms
如果采用预留空间的方式,读取一年的记录只需要6.6ms
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
MongoDB中更新文档的update()方法:1、命令为db.collection.update( criteria, objNew, upsert, multi );2、参数criteria用于指定一个查询,查询选择将要更新的目标记。
MongoDB是一个基于分布式文件存储的数据库,也是现在比较受欢迎的数据库之一,这篇文章主要给大家介绍的关于MongoDB优化的内容,感兴趣的朋友就跟随小编一起来了解吧。
MongoDB PHP 扩展 本教程将向大家介绍如何在Linux、window、Mac平台上安装MongoDB扩展。 Linux 上安装 MongoDB PHP 扩展 在终端上安装 你可以在 Linux 中执行以下命令来安装 MongoDB 的 PHP 扩展驱动 $ sudo pecl install mongodb 使用php的pecl安装命令必须保证网络连接可用以及root权限。 安装手册 如果你想通过源码来编译扩展驱动。你..
MongoDB中findOne()方法使用详解:如果输入的条件匹配多个文档,则该方法将根据自然顺序仅返回一个文档,这反映了文档在数据库中的存储顺序。
相信大家都知道mongodb是不支持join操作的,因此我们只能自己来实现这个功能。所以下面这篇文章主要给大家介绍了关于在MongoDB中如何使用JOIN操作的相关资料,文中通过示例代码介绍的非常详细,需要的朋友们下面来一起看看吧。
成为群英会员,开启智能安全云计算之旅
立即注册Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008