【发布时间】:2011-10-23 11:12:51
【问题描述】:
我应该什么时候调用 ensureIndex?在插入单条记录之前,插入单条记录之后,还是调用 find() 之前?
问候,
强尼
【问题讨论】:
我应该什么时候调用 ensureIndex?在插入单条记录之前,插入单条记录之后,还是调用 find() 之前?
问候,
强尼
【问题讨论】:
看来我的评论有点被误解了,所以我会澄清一下。何时调用它并不重要只要它在你第一次调用 find() 之前的某个时间点被调用。 换句话说,当你创建索引,只要它在您期望使用它之前就已经存在。
我经常看到的一个常见模式是在调用find() 的同时(并且在同一个地方)编码ensureIndex。 ensureIndex 将检查索引是否存在,如果不存在则创建它。在调用 find() 之前调用 ensureindex 无疑会有一些开销(尽管非常小),所以最好不要这样做。
我确实在代码中调用ensureIndex 以简化部署并避免必须分别管理数据库和代码库。易于部署的权衡平衡了后续调用 ensureIndex 的冗余(对我而言)。
【讨论】:
ensureIndex 是完全错误的:索引创建会锁定整个数据库,直到创建索引,即第一次查找可能需要几秒钟到几分钟,具体取决于集合大小。一个好的方法可能是在应用程序启动时使用一次ensureIndex/createIndex,但仍然要记住它会在创建过程完成之前锁定您的数据库。
我建议在您的应用程序启动时调用一次 ensureIndex。
【讨论】:
没关系,但您只需执行一次。如果你想批量插入大量数据到一个空集合中,那么最好在插入之后创建索引,否则就没有关系了。
【讨论】:
您只需执行一次。 示例:
db.table.insert({foo: 'bar'});
var foo = db.table.findOne({foo: 'bar'}); // => delivered from FS, not RAM
db.table.ensureIndex({foo: 1});
var foo = db.table.findOne({foo: 'bar'}); // => delivered from RAM, not FS
db.table.insert({foo: 'foo'});
var foo = db.table.findOne({foo: 'foo'}); // => delivered from RAM, not FS
【讨论】:
如果您事先添加索引,则每次插入/更新/删除调用也必须修改每个索引。因此,从优化的角度来看,您可能希望在发出查询之前尽可能地推迟它。但是,从功能的角度来看,这并不重要。
【讨论】:
我通常将我的 ensureIndex() 调用放在一个 init 块中,用于管理与 MongoDB 通信的应用程序部分。此外,我将那些ensureIndex() 调用包装在一个集合中,我知道该集合必须存在才能使应用程序运行;这样,ensureIndex() 调用只会在应用程序第一次针对特定 MongoDB 实例运行时被调用一次。
我在其他地方读到过反对将 ensureIndex() 调用放在应用程序代码中的意见,因为其他开发人员可能会错误地更改它们并更改数据库(索引),但是将其包装在一个集合是否存在的检查中有助于防止这个。
Java MongoDB 驱动示例:
DB db = mongo.getDB("databaseName");
Set<String> existingCollectionNames = db.getCollectionNames();
// init collections; ensureIndexes only if creating collection
// (let application set up the db if it's not already)
DBCollection coll = db.getCollection("collectionName");
if (!existingCollectionNames.contains("collectionName")) {
// ensure indexes...
coll.ensureIndex(BasicDBObjectBuilder.start().add("date", 1).get());
// ...
}
【讨论】:
如果您有一个包含数百万条记录的集合,并且您正在构建多个关闭自动索引的复合索引,那么您必须确保在第一次查找查询之前很长时间调用 ensureIndexes(),可能是同步的,即在 ensureIndexes 方法之后返回。
构建索引的模式(前景与背景)增加了额外的复杂性。前台模式在构建索引时锁定整个数据库,而后台模式允许您查询数据库。但是索引构建的后台模式需要额外的时间。
所以你必须确保索引已经创建成功。您可以使用 db.currentOp() 在 ensureIndexes() 仍在创建索引时检查它的进度。
【讨论】: