Pymongo / MongoDB:创建索引还是确保索引?
Posted
技术标签:
【中文标题】Pymongo / MongoDB:创建索引还是确保索引?【英文标题】:Pymongo / MongoDB: create index or ensure index? 【发布时间】:2011-08-20 05:42:59 【问题描述】:我不明白 pymongo 中 create_index
和 ensure_index
之间的区别。在MongoDB indexes page 上,它说
您可以通过调用
ensureIndex()
但是在pymongo中有两个不同的命令create_index
和ensure_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_index
和ensure_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_index
或ensure_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:创建索引还是确保索引?的主要内容,如果未能解决你的问题,请参考以下文章
使用 python 和 pymongo 的 MongoDB 位置运算符索引问题
使用 pyMongo 和 MongoEngine 从 MongoDb 列表中删除对象及其索引?