【问题标题】:Truncate a collection截断集合
【发布时间】:2013-05-11 04:58:08
【问题描述】:

我如何在 MongoDB 中截断一个集合,或者有这样的事情吗?

现在我必须一次删除 6 个大型集合,我正在停止服务器,删除数据库文件,然后重新创建数据库和其中的集合。有没有办法删除数据并使集合保持原样?删除操作需要很长时间。我的收藏中有数百万个条目。

【问题讨论】:

  • 你是怎么做删除操作的(当它需要很长时间时)?
  • db.collection.remove({ });
  • 啊!对于大型集合,remove() 命令将比drop()很多,因为它会在删除文档时执行更新索引的额外内务处理。如果您要删除集合中的所有文档,那么drop() 通常是最好的方法。删除和重新创建同一个集合需要注意的是,您还需要重新确保任何二级索引。

标签: mongodb mongodb-.net-driver


【解决方案1】:

截断集合并保留索引使用

 db.<collection>.remove({})

【讨论】:

  • 这可行,但索引大小保持不变。有没有办法截断索引,但仍然保留它们?
  • 请注意,但是 remove() 比 drop() 慢得多。
  • @rlib 是的,应该是 :)
  • @astroanu 是的,当然。上次我用 remove() 删除了 150 亿个文档,花了很长时间……实际上,长得令人无法接受。所以 drop() 、 createCollection() 和 createIndex() 是截断操作的唯一方法。
【解决方案2】:

您可以使用db.collection.drop() 有效地删除集合的所有数据和索引。删除包含大量文档和/或索引的集合将比使用db.collection.remove({}) 删除所有文档更有效。 remove() 方法会在删除文档时执行更新索引的额外内务管理,并且在 oplog 将包含删除的每个文档的条目而不是单个集合删除命令的副本集环境中会更慢。

使用mongo shell 的示例:

var dbName = 'nukeme';
db.getSiblingDB(dbName).getCollectionNames().forEach(function(collName) {
    // Drop all collections except system ones (indexes/profile)
    if (!collName.startsWith("system.")) {
        // Safety hat
        print("WARNING: going to drop ["+dbName+"."+collName+"] in 5s .. hit Ctrl-C if you've changed your mind!");
        sleep(5000);
        db[collName].drop();
    }
})

值得注意的是,根据配置的存储引擎,删除集合会对存储使用产生不同的影响:

  • WiredTiger(MongoDB 3.2 或更高版本中的默认存储引擎)将在删除完成后释放已删除集合(以及任何关联索引)使用的空间。
  • MMAPv1(MongoDB 3.0 及更早版本中的默认存储引擎)将 释放preallocated disk space。这可能适合您的用例;插入新数据时,可用空间可供重复使用。

如果您改为删除数据库,则通常不需要显式创建集合,因为它们将在插入文档时创建。

但是,下面是在mongo shell 中删除和重新创建具有相同集合名称的数据库的示例:

var dbName = 'nukeme';

// Save the old collection names before dropping the DB
var oldNames = db.getSiblingDB(dbName).getCollectionNames();

// Safety hat
print("WARNING: going to drop ["+dbName+"] in 5s .. hit Ctrl-C if you've changed your mind!")
sleep(5000)

db.getSiblingDB(dbName).dropDatabase();

// Recreate database with the same collection names
oldNames.forEach(function(collName) {
    db.getSiblingDB(dbName).createCollection(collName);
})

【讨论】:

  • 我忘了注意,如果您删除并重新创建集合,您还需要添加任何二级索引。您可以使用db.system.indexes.find() 列出现有的索引定义。
  • 在分区/分片集合上执行此操作不会造成严重破坏吗?
  • @zamnuts 感谢您的评论!在分片集群中删除和重用命名空间时发现了一个后续问题:SERVER-17397 - dropping a Database or Collection in a Sharded Cluster may not fully succeed。这是针对 MongoDB 2.6+ 报告的(如果早期版本有相同的问题,则未确认)。在该问题上有一个解决方法,其中涉及一些额外的步骤,以确保配置服务器已更新,并在重新创建命名空间之前清除 mongos 缓存。
  • 在实践中,这是一个坏主意。问题是删除一个集合也会删除它的索引,包括_id。如果您尝试立即删除并重新使用集合,mongodb 似乎在索引销毁的背景下,您可能会收到晦涩的错误消息“操作中止,因为:集合上的所有索引都已删除”。使用 remove() 更安全。
  • 删除集合会锁定它所在的数据库。因此,在频繁使用的 prod 数据库中执行此操作会因票证不足而导致性能影响。
【解决方案3】:

以下查询将删除集合中的所有记录并保持集合不变,

db.collectionname.remove({})

【讨论】:

    【解决方案4】:

    MongoDB 中没有与“截断”操作等效的操作。您可以删除所有文档,但复杂度为 O(n),或者删除集合,复杂度为 O(1),但您会丢失索引。

    【讨论】:

      【解决方案5】:

      创建数据库和集合,然后使用 mongodump 将数据库备份到 bson 文件:

      mongodump --db database-to-use
      

      然后,当您需要删除数据库并重新创建以前的环境时,只需使用 mongorestore:

      mongorestore --drop
      

      当您使用命令 mongodump 时,备份将保存在当前工作目录中名为 dump 的文件夹中。

      【讨论】:

      • 这将删除包括索引在内的所有内容
      • 谢谢!这正是我所需要的。
      【解决方案6】:

      remove() 在 MongoDB 4 中已弃用。

      您需要使用deleteMany或其他功能:

      db.<collection>.deleteMany({})
      

      【讨论】:

        【解决方案7】:

        db.drop() 方法在受影响的数据库上获得一个写锁,并将阻塞其他操作,直到它完成。

        我认为使用db.remove({}) 方法比db.drop() 更好。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-10
          • 1970-01-01
          • 2021-07-10
          • 2018-06-29
          • 2023-03-21
          相关资源
          最近更新 更多