在javascript shell和pymongo中的db.eval()的MongoDB性能

时间:2013-03-14 23:40:44

标签: performance mongodb profiling eval pymongo

我需要对需要在数组中旋转某些值的文档执行更新操作。 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)但现在,当我使用pymongo运行相同的eval()命令时:

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运行相同的命令需要多花14ms才能有根本的不同吗?

1 个答案:

答案 0 :(得分:1)

您看到的差异的一个可能原因(但不一定是 原因)是mongo shell和mongod服务器use Google's v8 Javascript engine默认情况下(虽然它可以配置为使用Spidermonkey作为替代)来解释您提供的命令。

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

另一方面,vanilla PyMongo是written in pure Python,这意味着它将永远被解释,这是一个相当大的开销。

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

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