Pymongo / MongoDB:创建索引还是确保索引?

Posted

技术标签:

【中文标题】Pymongo / MongoDB:创建索引还是确保索引?【英文标题】:Pymongo / MongoDB: create index or ensure index? 【发布时间】:2011-08-20 05:42:59 【问题描述】:

我不明白 pymongo 中 create_indexensure_index 之间的区别。在MongoDB indexes page 上,它说

您可以通过调用 ensureIndex()

但是在pymongo中有两个不同的命令create_indexensure_index,创建索引的文档有:

与 create_index() 不同,它尝试 无条件地创建索引, ensure_index() 利用了一些 在驱动程序中缓存,使其 只尝试创建索引 可能不存在。当一个索引 由 PyMongo 创建(或确保)它 被“记住” ttl 秒。 重复调用 ensure_index() 在该期限内将 轻量级 - 他们不会尝试 实际创建索引。

我是否正确理解 ensure_index 将创建一个永久索引,还是我需要为此使用 create_index

【问题讨论】:

在 mongo 3.x 中 ensureIndex 是 deprecated 因此最好停止使用它。即使你还在使用 2.6 版本,也最好提前做好准备,确保以后的迁移不会有什么意外。 【参考方案1】:

所有索引都是永久性的。 ensure_index() 只是 create_index() 的一个小包装。

""" ensureIndex() 函数仅在索引不存在时创建索引。 """

没有像临时索引或临时索引这样的东西。

【讨论】:

我认为这不太对。从 mongodb shell 调用 ensureIndex() 只会在索引不存在时创建索引。但是据我所知,从 python 接口调用ensure_index() 方法将创建一个索引或重建如果它不是最近创建的。【参考方案2】:

@andreas-jung 是正确的,ensure_index()create_index() 的包装,我认为这句话引起了混淆:

创建(或确保)索引时 通过 PyMongo,它被 ttl “记住” 秒。

并不是索引是临时的或“暂时的”,而是在指定的秒数内,调用ensure_index() 尝试再次创建相同的索引将不会有任何效果并且将不会在下面调用create_index(),但在“缓存”到期后,对ensure_index()的调用再次在下面调用create_index()

我完全理解您的困惑,因为坦率地说,PyMongo 的文档并不能很好地解释它是如何工作的,但是如果您转到 Ruby docs,解释会更清楚一些:

(String) ensure_index(spec, opts = )

调用 create_index 并将标志设置为 再过 X 分钟不要再这样做了。 这个时间可以指定为 初始化 Mongo::DB 时的选项 对象作为选项[:cache_time] 任何 将传播对索引的更改 通过不考虑缓存时间 (例如,改变索引方向)

用于此的参数和选项 方法与那些相同 集合#create_index。

例子:

Call sequence:

Time t: @posts.ensure_index([['subject', Mongo::ASCENDING]) -- calls create_index and sets the 5 minute cache

Time t+2min : @posts.ensure_index([['subject', Mongo::ASCENDING]) -- doesn't do anything

Time t+3min : @posts.ensure_index([['something_else', Mongo::ASCENDING]) -- calls create_index and sets 5 minute cache

Time t+10min : @posts.ensure_index([['subject', Mongo::ASCENDING]) -- calls create_index and resets the 5 minute counter

我并不是说驱动程序的工作方式完全相同,只是为了便于说明,恕我直言,他们的解释要好一些。

【讨论】:

【参考方案3】:

Interactive Shell 中的ensureIndex 方法和python 驱动程序中的ensure_index 是不同的东西,尽管使用的是同一个词。 python 驱动程序中的create_indexensure_index 方法都会永久创建索引。

在这种情况下,也许有人会使用具有合理 TTL 的ensure_index,因为我不确定create_index 是否会在您每次调用它时重新创建索引。通常不需要娱乐,这可能是一项繁重的操作。但即使是ensure_index(python 或 ruby​​ 驱动程序)也可能在 TTL 过期或从不同客户端实例调用它或重新启动后重新创建索引。我不确定。

也许更好的方法是首先使用index_information() 方法检查索引是否已经存在。如果它已经存在,您将不会再次创建它。

我现在正在演示如何使用术语 ensure_index(或 ensureIndex)以两种不同的含义:

1) 如果数据库中尚不存在索引,则创建索引

这就是 Interactive Shell 方法 ensureIndex() 所做的:

http://www.mongodb.org/display/DOCS/Indexes#Indexes-Basics

Node.JS MongoDB Driver 也有这种行为:

https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/collection.js

(在文件collection.js中搜索function ensureIndex。)

2) 如果它不在“驱动程序缓存”中,它会创建一个索引

这里使用相同的标识符具有不同的含义,我觉得这很混乱。

python 和 ruby​​ 驱动程序将有关最近创建的索引的信息存储在内存中,他们称这种行为为“缓存”。

他们不会告诉数据库这个缓存。

这种机制的结果是,如果你第一次调用create_indexensure_index时带有一个TTL值(生存时间),那么驱动程序会在数据库中插入索引并且会记住这个插入并且还将TTL信息存储在内存中。这里缓存的是时间和是哪个索引。

下次您在同一驱动程序实例上使用同一集合的同一索引调用ensure_index 时,如果自第一次调用以来还没有经过 TTL 秒,ensure_index 命令只会再次插入索引。

如果您调用create_index,索引将始终被插入,无论从第一次调用后经过了多少时间,当然如果这是第一次调用也是如此。

这是python驱动,在文件collection.py中搜索def ensure_index

https://github.com/mongodb/mongo-python-driver/blob/master/pymongo/collection.py

还有ruby驱动,在文件collection.rb中搜索def ensure_index

https://github.com/mongodb/mongo-ruby-driver/blob/master/lib/mongo/collection.rb

(请注意,不同的客户端实例不知道其他客户端实例的缓存,此信息仅保存在内存中,并且是每个实例的。如果您重新启动客户端应用程序,新实例不知道旧的“缓存”索引插入。其他客户端也不知道,他们不会互相告诉。)

我还不能完全理解,当 python 驱动程序或 ruby​​ 驱动程序插入一个已经存在的索引时,数据库中会发生什么。我怀疑他们在这种情况下什么都不做,这更有意义,也符合Interactive Shell 和 JS 驱动程序的行为。

【讨论】:

【参考方案4】:

我建议创建元类和 ORM。 从元类 init 调用 init_schema 方法来初始化计数器、模式、键等。 这样可以防止在每次查询或集合更新时调用 ensure_index :)

【讨论】:

【参考方案5】:

请记住,在 Mongo 3.x 中,ensureIndex 已被弃用,应该不鼓励使用。

自 3.0.0 版起已弃用:db.collection.ensureIndex() 现在是 db.collection.createIndex() 的别名。

pymongo:

已弃用 - 确保此集合上存在索引。

这意味着您应该始终使用create_index

【讨论】:

【参考方案6】:

您应该使用 create_index 代替因为他们在答案和文档本身中所说的 ensureIndex() 已被弃用,https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/#recreating-an-existing-index 这就是您应该使用 create_index 的原因 ,正如他们所说的

“如果你为已经存在的索引调用 db.collection.createIndex(),MongoDB 不会重新创建索引。”

【讨论】:

以上是关于Pymongo / MongoDB:创建索引还是确保索引?的主要内容,如果未能解决你的问题,请参考以下文章

一日一技:MongoDB如何正确中断正在创建的索引

如何使用 pymongo 创建索引 [重复]

使用 python 和 pymongo 的 MongoDB 位置运算符索引问题

使用 pyMongo 和 MongoEngine 从 MongoDb 列表中删除对象及其索引?

如何跳过重复索引上的错误并继续在 MongoDB 中进一步添加文档(pymongo)

将 Pymongo 数据从列表附加到 pandas 数据框