16

我需要对需要在数组中旋转一些值的文档执行更新操作。MongoDB 更新查询目前不允许您$pop$push对同一字段进行更新。在网上搜索了建议后,我决定这db.eval()将最适合我的使用,因为它确保了原子性并且我正在执行的操作非常短,因此它不会锁定数据库太久。

这是我正在尝试做的事情的一个例子:

db.eval(function (id, newVal) {
    doc = db.collection.findOne({_id: id});
    doc.values.shift();
    doc.values.push(newVal);
    db.collection.save(doc);
}, id, newVal);

这非常有效!然后我启用了 mongoDB 分析以查看命令花费了多少毫秒,eval()并且我总是得到少于 1 毫秒的结果:

 > db.system.profile.find({op: "command"}, {"millis": 1}) 
 { "millis" : 0 }
 { "millis" : 0 }
 ...

这对我来说是个好消息,除了我的应用程序是在 python 中,所以我使用 pymongo 客户端来执行eval()命令。(上面的数据来自 mongo shell)但是现在,当我eval()使用 pymongo 运行相同的命令时:

conn = pymongo.Connection(mongo_server_hostname)
db = conn.my_db

db.eval("""function (id, newVal) {
    doc = db.collection.findOne({_id: id});
    doc.values.shift();
    doc.values.push(newVal);
    db.collection.save(doc);
}""", id, new_val)

我得到了非常不同的分析结果:

> db.system.profile.find({op: "command"}, {"millis": 1}) 
{ "millis" : 13 }
{ "millis" : 14 }
{ "millis" : 14 }
...

从 mongo shell 和 pymongo 中运行相同的命令是否有根本的不同eval(),导致服务器从 pymongo 运行相同的命令要多花 14 毫秒?

4

1 回答 1

1

您看到的差异的一个可能原因(但不一定mongo原因)是shell 和mongod服务器默认使用 Google 的 v8 Javascript 引擎(尽管它可以配置为使用 Spidermonkey 作为替代)来解释命令你给。

Google 的 v8 在 Javascript 代码中看到了热点,并且很可能是经常使用的 JIT 代码。

另一方面,vanilla PyMongo 是用纯 Python 编写的,这意味着它总是会被解释,这是一个相当大的开销。

如果您还没有这样做,一种可能性是使用用 C 编写的 PyMongo 扩展而不是默认扩展,或者,如果您的应用程序的其余部分兼容,则使用 Python 的 PyPy JIT 解释器。

如果您使用任何从 Debian 派生的发行版(如 Ubuntu),python-pymongo-ext包会为您提供 PyMongo C 版本的预编译版本。

于 2013-04-22T08:39:44.937 回答