Mongodb:啥时候调用ensureIndex?

Posted

技术标签:

【中文标题】Mongodb:啥时候调用ensureIndex?【英文标题】:When to call ensureIndex on a MongoDB collection?Mongodb:什么时候调用ensureIndex? 【发布时间】:2011-10-23 11:12:51 【问题描述】:

我应该什么时候调用 ensureIndex?在插入单条记录之前,插入单条记录之后,还是调用 find() 之前?

问候,

强尼

【问题讨论】:

【参考方案1】:

看来我的评论有点被误解了,所以我会澄清一下。何时调用它并不重要只要它在你第一次调用 find() 之前的某个时间点被调用。 换句话说,当你创建索引,只要它在您期望使用它之前就已经存在。

我经常看到的一个常见模式是在调用find() 的同时(并且在同一个地方)编码ensureIndexensureIndex 将检查索引是否存在,如果不存在则创建它。在调用 find() 之前调用 ensureindex 无疑会有一些开销(尽管非常小),所以最好不要这样做。

我确实在代码中调用ensureIndex 以简化部署并避免必须分别管理数据库和代码库。易于部署的权衡平衡了后续调用 ensureIndex 的冗余(对我而言)。

【讨论】:

开销如何? mongo 在幕后做了什么?我知道它是 B-Tree,当添加一个新 doc 时,它在树中的什么位置? EnsureIndex 基本上是测试指定索引是否存在,如果不存在则创建它。进行该检查的开销很小。除此之外,每个索引都会在写入时产生开销,我们的目标是仔细选择您的索引,这样您在读取上获得的收益比在写入上产生的开销要大。 考虑到 mongo 的吞吐量可以实现两倍的命令量,不管 ensureIndex early-out 本身的效率如何,都会引入显着的带宽开销。我当然会避免做超出需要的事情。 感谢您的这篇文章,它今天仍然适用。我遇到了一些奇怪的错误,似乎 mongo 正在吞噬我的索引。我看到了你关于在其他任何事情之前调用它的评论,我想我现在已经弄清楚了。 @CodeMagician 请编辑您的答案。在每次查找之前调用 ensureIndex 是完全错误的:索引创建会锁定整个数据库,直到创建索引,即第一次查找可能需要几秒钟到几分钟,具体取决于集合大小。一个好的方法可能是在应用程序启动时使用一次ensureIndex/createIndex但仍然要记住它会在创建过程完成之前锁定您的数据库【参考方案2】:

我建议在您的应用程序启动时调用一次 ensureIndex。

【讨论】:

来源:docs.mongodb.org/manual/faq/indexes/… 这不是我的“来源”,但它有效地表达了同样的意思。 想澄清一下。我不需要对默认提供的 id 使用 ensureIndex 吗?【参考方案3】:

没关系,但您只需执行一次。如果你想批量插入大量数据到一个空集合中,那么最好在插入之后创建索引,否则就没有关系了。

【讨论】:

【参考方案4】:

您只需执行一次。 示例:

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

【讨论】:

所有这些都将从 RAM 中交付。索引!= RAM。 mongodb.org/display/DOCS/…. 请引用说明这一点的部分 @TimvanElsloo - 我认为值得一提的是,操作系统可以从 Mongo 手中夺走 RAM。因此,对于每第二次和第三次 find(),您总是会访问 RAM,这是否具有引用透明性?在 Karoly,您能解释一下您的第一条评论吗?【参考方案5】:

如果您事先添加索引,则每次插入/更新/删除调用也必须修改每个索引。因此,从优化的角度来看,您可能希望在发出查询之前尽可能地推迟它。但是,从功能的角度来看,这并不重要。

【讨论】:

【参考方案6】:

我通常将我的 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());
    // ...

【讨论】:

【参考方案7】:

如果您有一个包含数百万条记录的集合,并且您正在构建多个关闭自动索引的复合索引,那么您必须确保在第一次查找查询之前很长时间调用 ensureIndexes(),可能是同步的,即在 ensureIndexes 方法之后返回。

构建索引的模式(前景与背景)增加了额外的复杂性。前台模式在构建索引时锁定整个数据库,而后台模式允许您查询数据库。但是索引构建的后台模式需要额外的时间。

所以你必须确保索引已经创建成功。您可以使用 db.currentOp() 在 ensureIndexes() 仍在创建索引时检查它的进度。

【讨论】:

以上是关于Mongodb:啥时候调用ensureIndex?的主要内容,如果未能解决你的问题,请参考以下文章

MongoDB中喜欢的EnsureIndex

MongoDB 使用 ensureIndex 删除重复项,但保留最后一个条目而不是第一个条目

MongoDB ensureIndex 是不是执行重建?

MongoDB创建索引

MongoDB索引的基本用法

mongodb索引