绝好的MongoDB学习资料之六. Optimization
2012-01-09 15:45
330 查看
1. Profiler
MongoDB 自带 Profiler,可以非常方便地记录下所有耗时过长操作,以便于调优。
通常我们只关心 Slow Operation,Level 1 默认记录 >100ms 的操作,当然我们也可以自己调整 "db.setProfilingLevel(2, 300)"。
Profiler 信息保存在 system.profile (Capped Collection) 中。
准备 1000000 条数据测试一下。
开始调优操作。
system.profile 中记录下一条耗时过长的操作。
ts: 操作执行时间。
info: 操作详细信息。
info.query: 查询目标(数据库.集合)。
info.ntoreturn: 客户端期望返回的文档数量。
info.nscanned: 服务器实际扫描的文档数量。
info.reslen: 查询结果字节长度。
info.nreturnned: 查询返回文档数。
millis: 操作耗时(毫秒)。
很显然,该操作扫描的文档过多(info.nscanned),通常是没有使用索引造成的。我们用 explain() 看看服务器如何执行执行该命令。
没有索引自然很慢了,建个索引看看效果。
速度提升非常明显。最后别忘了 Profiler 本身也会影响服务器性能,不用的时候要关掉。
除了使用 setProfilingLevel 命令外,也可以在 mongod 参数中启用 profiler,不推荐。
2. Optimization
优化建议:
如果 nscanned 远大于 nreturned,那么需要使用索引。
如果 reslen 返回字节非常大,那么考虑只获取所需的字段。
执行 update 操作时同样检查一下 nscanned,并使用索引减少文档扫描数量。
使用 db.eval() 在服务端执行某些统计操作。
减少返回文档数量,使用 skip & limit 分页。
MongoDB 自带 Profiler,可以非常方便地记录下所有耗时过长操作,以便于调优。
> db.setProfilingLevel(n) n: 0: Off; 1: Log Slow Operations; 2: Log All Operations.
通常我们只关心 Slow Operation,Level 1 默认记录 >100ms 的操作,当然我们也可以自己调整 "db.setProfilingLevel(2, 300)"。
Profiler 信息保存在 system.profile (Capped Collection) 中。
准备 1000000 条数据测试一下。
>>> from pymongo import * >>> from random import randint >>> conn = Connection() >>> db = conn.blog >>> for i in xrange(1000000): u = dict(name = "user" + str(i), age = randint(10, 90)) 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() 看看服务器如何执行执行该命令。
> db.users.find().sort({age:-1}).limit(10000).explain() { "cursor" : "BasicCursor", "nscanned" : 1000000, "nscannedObjects" : 1000000, "n" : 10000, "scanAndOrder" : true, "millis" : 1412, "indexBounds" : { } }
没有索引自然很慢了,建个索引看看效果。
> db.users.ensureIndex({age:-1}) > db.users.find().sort({age:-1}).limit(10000).explain() { "cursor" : "BtreeCursor age_-1", "nscanned" : 10000, "nscannedObjects" : 10000, "n" : 10000, "millis" : 211, "indexBounds" : { "age" : [ [ { "$maxElement" : 1 }, { "$minElement" : 1 } ] ] } }
速度提升非常明显。最后别忘了 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 分页。
相关文章推荐
- 绝好的MongoDB学习资料之四. Index
- 绝好的MongoDB学习资料之五. Admin
- 绝好的MongoDB学习资料之七. Replication (1)
- 绝好的MongoDB学习资料之八. Replication (2)
- 绝好的MongoDB学习资料之十一. Grid FS
- 绝好的MongoDB学习资料之十二 MapReduce
- 绝好的MongoDB学习资料之一. Database
- 绝好的MongoDB学习资料之二. Basic Usage
- 绝好的MongoDB学习资料之三. Schema Design
- mongodb 学习资料
- mongodb学习资料
- 绝好的MongoDB学习资料之九. Sharding (1)
- mongodb(NoSQL非关系型数据库)学习资料
- 学习MongoDB在java中使用的官方资料
- Spring MVC 3.1 Update - 绝好的Spring MVC 3.1学习资料共112页
- MongoDB 学习资料整理
- 绝好的MongoDB学习资料之十. Sharding (2)
- MongoDB 学习资料
- 绝好的Redis学习资料,讲的很系统
- MongoDB学习资料