原文地址:http://www.oschina.net/translate/things-i-wish-i-knew-about-mongodb-a-year-ago?from=20130630
参与翻译(4人):
桔子, super0555, Liam_Lee, lxbzmy
在Heyzap 和 Bugsnag 我已经使用MongoDB超过一年了,我发现它是一个非常强大的数据库。和其他的数据库一样,它有一些缺陷,但是这里有一些东西我希望有人可以早一点告诉我的。 即使建立索引选择性计数还是很缓慢
举个例子,当对用户feed进行分页时,你可能会看到类似的东西,
1db.collection.count({username: "my_username"}); 在MongoDB,这种计数采取的数量级的时间比你希望的要长。有一个open ticke,目前为2.4,在这里,我希望希望他们可以将它弄出来。在那之前,你可以留下自己的数据汇总。在插入一个新的文档的时候,你可以在mongo中用$inccommand存储数据汇总。 副本集读取不一致
当你开始利用副本集跨集群分发读数结果,就会使自己卷入麻烦的漩涡。例如,如果你将数据写到主设备,随后的读操作可能会被指引到从设备,而从设备尚有待拷贝数据。可以用类似下面的例子来说明这一点,
1// Writes the object to the primary2db.collection.insert({_id: ObjectId("505bd76785ebb509fc183733"), key: "value"});34// This find is routed to a read-only secondary, and finds no results5db.collection.find({_id: ObjectId("505bd76785ebb509fc183733")}); 如果还有性能问题的话这个问题会更复杂,因为这会导致主设备与从设备之间的复制滞后,使其增长到数分钟乃至某些情况下的数小时。
你既可以控制一次查询是否运行于从设备,也可以控制在插入操作中有多少从设备执行复制操作,但是这将影响到性能,在某些情况甚至会引起永久阻塞! 范围查询被以不同顺序索引
我发现范围查询使用的索引与其他的查询有些许不同。一般在一次复合查询中,你会用关键字作为索引操作的后一个参数。然而,在使用诸如$in之类的范围查询时,Mongo在应用该范围前就应用了索引。这会导致对文档的索引是在内存中完成,而这相当的慢!
view sourceprint?1// This doesn't use the last element in a compound index to sort2db.collection.find({_id: {$in: [3ObjectId("505bd76785ebb509fc183733"),4ObjectId("505bd76785ebb509fc183734"),5ObjectId("505bd76785ebb509fc183735"),6ObjectId("505bd76785ebb509fc183736")7]}}).sort({last_name: 1}); 在Heyzap,我们通过为这个查询在Redis中创建一个缓存层,从而绕过了这个问题。但如果在$in声明中你只有两个数值,你也可以执行同样的查询两次,或者如果你有可用的RAM,你也可以调整这个索引。
你可以读到更多关于这个问题的内容,或者浏览此标签。 Mongo的 BSON>
Mongo的 BSON>1// Will return the time the ObjectId was created2ObjectId("505bd76785ebb509fc183733").getTimestamp();
BSON>索引所有的查询
当我第一次使用Mongo时,我有时候会在特定的基础环境上或从一个定时任务中执行查询。最初那些查询并没有被索引,因为不需要面对用户也不需要经常运行。然而这给别的索引查询带来了性能问题,因为未索引的查询会做大量的磁盘读操作,这影响到对未缓存文档的检索。于是我下决心要保证那些查询至少是部分索引的,以免这样的事情再次发生。 始终对新建的查询执行explain操作
显然,如果你有关系数据库的使用背景,你一定熟悉 explain操作,这在Mongo里面同样重要。当你为一个应用新增一个查询时,你应该在生产数据上运行一下查询以检查其速度。你也可以要求Mongo执行explain 来解释查询到底怎么执行的,以便于你可以检查索引之类的参数等等。
view sourceprint?01db.collection.find(query).explain()02{03// BasicCursor means no index used, BtreeCursor would mean this is an indexed query04"cursor": "BasicCursor",0506// The bounds of the index that were used, see how much of the index is being scanned07"indexBounds": [ ],0809// Number of documents or indexes scanned10"nscanned": 57594,1112// Number of documents scanned13"nscannedObjects": 57594,1415// The number of times the read/write lock was yielded16"nYields": 2 ,1718// Number of documents matched19"n": 3 ,2021// Duration in milliseconds22"millis": 108,2324// True if the results can be returned using only the index25"indexOnly": false,2627// If true, a multikey index was used28"isMultiKey": false29} 我曾见过新部署的应用程序就因为其中的查询语句没有在生产环境中做验证而导致的整个站点down掉。做个验证是相对快速和容易做到的,所以不要找拒绝!