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

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

问候,

强尼

【问题讨论】:

    标签: mongodb indexing


    【解决方案1】:

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

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

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

    【讨论】:

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

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

    【讨论】:

    • 这不是我的“来源”,但它有效地表达了同样的意思。
    • 想澄清一下。我不需要对默认提供的 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。
      • 请引用说明这一点的部分
      • @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() 仍在创建索引时检查它的进度。

          【讨论】:

            猜你喜欢
            • 2019-12-25
            • 1970-01-01
            • 2014-03-27
            • 1970-01-01
            • 2010-10-18
            • 2016-03-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多