Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5375567
  • 博文数量: 1144
  • 博客积分: 11974
  • 博客等级: 上将
  • 技术积分: 12312
  • 用 户 组: 普通用户
  • 注册时间: 2005-04-13 20:06
文章存档

2017年(2)

2016年(14)

2015年(10)

2014年(28)

2013年(23)

2012年(29)

2011年(53)

2010年(86)

2009年(83)

2008年(43)

2007年(153)

2006年(575)

2005年(45)

分类: Mysql/postgreSQL

2013-03-29 15:02:39

:1. Profiler MongoDB 自带 Profiler,可以非常方便地记录下所有耗时过长操作,以便于调优。 db.setProfilingLevel(n) n: 0:Off; 1:LogSlowOperations; 2:LogAllOperations. 通常我们只关心 Slow Operation,Level 1 默认记录 1
1. Profiler

MongoDB 自带 Profiler,可以非常方便地记录下所有耗时过长操作,以便于调优。


1.> db.setProfilingLevel(n)  2. 3.n:   4.   0: Off;   5.   1: Log Slow Operations;   6.   2: Log All Operations. 


通常我们只关心 Slow Operation,Level 1 默认记录 >100ms 的操作,当然我们也可以自己调整 "db.setProfilingLevel(2, 300)"。

Profiler 信息保存在 system.profile (Capped Collection) 中。

准备 1000000 条数据测试一下。


1.>>> from pymongo import *  2.>>> from random import randint  3.>>> conn = Connection()  4.>>> db = conn.blog  5. 6.>>> for i in xrange(1000000):  7.    u = dict(name = "user" + str(i), age = randint(10, 90))  8.    db.users.insert(u) 


开始调优操作。


> db.setProfilingLevel(1)

{ "was" : 0, "ok" : 1 }

> db.users.find().sort({age:-1}).limit(10000)

{ "_id" : ObjectId("4c50dc07499b1404c60f42e5"), "age" : 90, "name" : "user165" }

{ "_id" : ObjectId("4c50dc07499b1404c60f42e8"), "age" : 90, "name" : "user168" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4350"), "age" : 90, "name" : "user272" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4358"), "age" : 90, "name" : "user280" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4375"), "age" : 90, "name" : "user309" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4433"), "age" : 90, "name" : "user499" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4480"), "age" : 90, "name" : "user576" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4484"), "age" : 90, "name" : "user580" }

{ "_id" : ObjectId("4c50dc07499b1404c60f44cf"), "age" : 90, "name" : "user655" }

{ "_id" : ObjectId("4c50dc07499b1404c60f44fb"), "age" : 90, "name" : "user699" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4517"), "age" : 90, "name" : "user727" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4688"), "age" : 90, "name" : "user1096" }

{ "_id" : ObjectId("4c50dc07499b1404c60f46a8"), "age" : 90, "name" : "user1128" }

{ "_id" : ObjectId("4c50dc07499b1404c60f46ae"), "age" : 90, "name" : "user1134" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4740"), "age" : 90, "name" : "user1280" }

{ "_id" : ObjectId("4c50dc07499b1404c60f479b"), "age" : 90, "name" : "user1371" }

{ "_id" : ObjectId("4c50dc07499b1404c60f479d"), "age" : 90, "name" : "user1373" }

{ "_id" : ObjectId("4c50dc07499b1404c60f480f"), "age" : 90, "name" : "user1487" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4842"), "age" : 90, "name" : "user1538" }

{ "_id" : ObjectId("4c50dc07499b1404c60f4844"), "age" : 90, "name" : "user1540" }

has more

> db.system.profile.find()

{

"ts" : "Thu Jul 29 2010 09:47:47 GMT+0800 (CST)",

"info" : "query blog.users

ntoreturn:10000 scanAndOrder

reslen:518677

nscanned:1000000

query: { query: {}, orderby: { age: -1.0 } }

nreturned:10000 1443ms",

"millis" : 1443

}
 


system.profile 中记录下一条耗时过长的操作。

??ts: 操作执行时间。
??info: 操作详细信息。
??info.query: 查询目标(数据库.集合)。
??info.ntoreturn: 客户端期望返回的文档数量。
??info.nscanned: 服务器实际扫描的文档数量。
??info.reslen: 查询结果字节长度。
??info.nreturnned: 查询返回文档数。
??millis: 操作耗时(毫秒)。
很显然,该操作扫描的文档过多(info.nscanned),通常是没有使用索引造成的。我们用 explain() 看看服务器如何执行执行该命令。


1.> db.users.find().sort({age:-1}).limit(10000).explain()  2.{  3.        "cursor" : "BasicCursor",  4.        "nscanned" : 1000000,  5.        "nscannedObjects" : 1000000,  6.        "n" : 10000,  7.        "scanAndOrder" : true,  8.        "millis" : 1412,  9.        "indexBounds" : {  10. 11.        }  12.} 


没有索引自然很慢了,建个索引看看效果。


1.> db.users.ensureIndex({age:-1})  2. 3.> db.users.find().sort({age:-1}).limit(10000).explain()  4.{  5.        "cursor" : "BtreeCursor age_-1",  6.        "nscanned" : 10000,  7.        "nscannedObjects" : 10000,  8.        "n" : 10000,  9.        "millis" : 211,  10.        "indexBounds" : {  11.                "age" : [  12.                        [  13.                                {  14.                                        "$maxElement" : 1  15.                                },  16.                                {  17.                                        "$minElement" : 1  18.                                }  19.                        ]  20.                ]  21.        }  22.} 

速度提升非常明显。最后别忘了 Profiler 本身也会影响服务器性能,不用的时候要关掉。


> db.setProfilingLevel(0)

{ "was" : 1, "ok" : 1 }
 

 

除了使用 setProfilingLevel 命令外,也可以在 mongod 参数中启用 profiler,不推荐。


--profile arg 0=off 1=slow, 2=all

--slowms arg (=100) value of slow for profile and console log
 


2. Optimization

优化建议:

??如果 nscanned 远大于 nreturned,那么需要使用索引。
??如果 reslen 返回字节非常大,那么考虑只获取所需的字段。
??执行 update 操作时同样检查一下 nscanned,并使用索引减少文档扫描数量。
??使用 db.eval() 在服务端执行某些统计操作。
??减少返回文档数量,使用 skip & limit 分页。

 

阅读(1247) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~