论坛首页 编程语言技术论坛

mongoDB性能初测与优化

浏览 9393 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-04-06  

测试环境:

  型号名称:    iMac
  处理器名称:    Intel Core 2 Duo
  处理器速度:    3.06 GHz
  处理器数量:    1
  总核心数:    2
  L2 高速缓存:    3 MB
  内存:    4 GB
  总线速度:    1.07 GHz

测试方案:

用js脚本创建向一个collection里插入一百万个文档,测量mongo占用内存,硬盘数据文件大小(优化数据库设计),插入时间,在一百万条基础上做find操作。

 

内存:

起动mongod之后,可用内存是2.65G. 创建完1百万条记录后,可用内存为1.34G. 说明在创建过程中审请过约1.3G内存,用完了其它程序可接着使用。

索引内存:300M,容易记的是100万个文档,3个索引字段(加系统_id),300M。

> db.process.totalIndexSize()
302638016

 

 

#导入100万个文档

db.serverStatus().mem
{
    "bits" : 64,
    "resident" : 530,
    "virtual" : 6386,
    "supported" : true,
    "mapped" : 3952
}

#未做查询
    "mem" : {
        "bits" : 64,
        "resident" : 4,
        "virtual" : 2399,
        "supported" : true,
        "mapped" : 0
    },

#做完查询
    "mem" : {
        "bits" : 64,
        "resident" : 20,
        "virtual" : 3375,
        "supported" : true,
        "mapped" : 976
    },


从以上测试来看,在生产环境下,最好预留1-2G的内存给mongod!

 

 

时间:


创建完100万个文档,时间, 3分20秒 左右(多次测试)

baicaomatoiMac:mongo baicao$ time mongo process_task.js
MongoDB shell version: 1.6.2
connecting to: test

real    3m22.432s
user    3m14.673s
sys    0m6.514s

find查询:
击中索引,基本只需要0ms(测不到),  最坏的情况也是在26ms(第一次查询),mongo在查询之后就有cach,后面基本就是0ms了。
> db.process.find({"index.task_name":"ReturnMoney","index.user_id":100,"index.status":1}).explain()
{
    "cursor" : "BtreeCursor index.task_name_1_index.user_id_1_index.status_1",
    "nscanned" : 50,
    "nscannedObjects" : 50,
    "n" : 50,
    "millis" : 0,
    "indexBounds" : {
        "index.task_name" : [
            [
                "ReturnMoney",
                "ReturnMoney"
            ]
        ],
        "index.user_id" : [
            [
                100,
                100
            ]
        ],
        "index.status" : [
            [
                1,
                1
            ]
        ]
    }
}

不是完全击中索引,加上process_id(非索引字段)这个查询条件,速度也是非常快,基本只要1ms, 最差在8ms(第一次)。即先用索引击中100或200条记录,再在这百条记录里查找process_id,也是非常快。

 

这给我们一个启示,只对最关键的字段做索引。有些字段可以让mongo去遍历的。 如果都做成索引,那索引太大,需要的内存就要非常大!


> db.process.find({"index.task_name":"Precontract","index.user_id":100,"index.status":1, process_id:0}).explain()
{
    "cursor" : "BtreeCursor index.task_name_1_index.user_id_1_index.status_1",
    "nscanned" : 100,
    "nscannedObjects" : 100,
    "n" : 100,
    "millis" : 1,
    "indexBounds" : {
        "index.task_name" : [
            [
                "Precontract",
                "Precontract"
            ]
        ],
        "index.user_id" : [
            [
                100,
                100
            ]
        ],
        "index.status" : [
            [
                1,
                1
            ]
        ]
    }
}

如果没有索引,一百万条记录,对4个字段查找(遍历),要1000ms左右。
速度还是非常快,但离可用性还是有距离。

 

缩小数据库文件大小

 

MongoDB查询能力强,性能好,但代价是内存开销大,数据库文件大。每个文档都有字段定义!

 

用第一个脚本创建:process_task.js(见附件)创建,100万条文档需要2G-3G大小的数据库文件。

 

文件大小: 128 + 256 + 512 + 1024 + 1024 * 2  = 3968 M, 约4G, 最后的2G可能没怎么用,那最小也在2G左右
-rw-------  1 root  admin   134217728  4  1 10:28 genius_t_1.1
-rw-------  1 root  admin   268435456  4  1 10:28 genius_t_1.2
-rw-------  1 root  admin   536870912  4  1 10:28 genius_t_1.3
-rw-------  1 root  admin  1073741824  4  1 10:28 genius_t_1.4
-rw-------  1 root  admin  2146435072  4  1 10:27 genius_t_1.5

用mongo自带命令查看

 

genius_t_1:  663M, 每个文档平均大小是544!

> db.printCollectionStats()
process
{
    "ns" : "genius_t_1.process",
    "count" : 1000000,
    "size" : 544000000,
    "avgObjSize" : 544,
    "storageSize" : 663950336,
    "numExtents" : 20,
    "nindexes" : 2,
    "lastExtentSize" : 117793792,
    "paddingFactor" : 1,
    "flags" : 1,
    "totalIndexSize" : 302638016,
    "indexSizes" : {
        "_id_" : 41394176,
        "index.task_name_1_index.user_id_1_index.status_1" : 261243840
    },
    "ok" : 1
}

用process_task_short.js创建,把process_id 简写为pid, user_id, 简写为uid, task_name, 简写为name

 

genius_t_2: 616M, 每个文档平均大小是508!

process
{
    "ns" : "genius_t_2.process",
    "count" : 1000000,
    "size" : 508000000,
    "avgObjSize" : 508,
    "storageSize" : 616527872,
    "numExtents" : 20,
    "nindexes" : 2,
    "lastExtentSize" : 109380352,
    "paddingFactor" : 1,
    "flags" : 1,
    "totalIndexSize" : 302638016,
    "indexSizes" : {
        "_id_" : 41394176,
        "index.name_1_index.uid_1_index.state_1" : 261243840
    },
    "ok" : 1
}

用process_task_short_short.js创建,把手机号用整数方式来存,再一步缩短字段名。

 

genius_t_3 : 499M, 每个文档平均大小是460, 比最初的544,下降了15%的空间 。数据库文件上也没有出来2G的那个文件了。所以,这种优化还是非常值的,就是可读性略有下降。但只对约定的字段进行简缩,并没有对任务名进行缩简。

process
{
    "ns" : "genius_t_3.process",
    "count" : 1000000,
    "size" : 460000136,
    "avgObjSize" : 460.000136,
    "storageSize" : 499348736,
    "numExtents" : 19,
    "nindexes" : 2,
    "lastExtentSize" : 89748992,
    "paddingFactor" : 1,
    "flags" : 1,
    "totalIndexSize" : 284779456,
    "indexSizes" : {
        "_id_" : 41394176,
        "index.name_1_index.uid_1_index.mob_1" : 243385280
    },
    "ok" : 1
}

总结:

 

1.  mongoDB占用内存挺大的,虚拟内存都是1G以上,随着查询,会用更多的内存(索引)被进驻,生产环境最好留1-2G给mongoDB

 

2. mongoDB的性能非常好,在有索引的情况下,0ms。没有必要所有的字段都做成索引,先用索引确定几百个文档,对非索引字段进行遍历,也只需要1ms。

 

3. mongoDB的数据库文件也非常大,100万条文档也有在1G以上。所以数据库设计时,在保证可读性性的前提下,尽量缩短字段名 。像常用的字段(约定俗成)长度最好在5个字符以下。参考测试附件。

 

附件:

 

测试脚本:

   发表时间:2011-04-17  
我一直担心的就是内存问题,好像没有办法限制内存大小,据说要求内存足够装下所有数据才行,这点我还没有测试过,不知道超过只会导致性能损失,还是内存溢出的异常呢。
0 请登录后投票
   发表时间:2011-04-18  
内存如果不够大,没有装入所有索引,效率上相差还是挺多的
0 请登录后投票
   发表时间:2011-04-18   最后修改:2011-04-18
seekboy 写道
内存如果不够大,没有装入所有索引,效率上相差还是挺多的


内存不够的情况,效率差到什么程度? 和mysql的比较有多大差别? 当然首先得知道是否能正常运行?
0 请登录后投票
   发表时间:2012-03-30  
数据库大小超过内存的时候的性能。 mongodb的性能不怎么样
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics