mongooose/mongodb流vs数组性能

问题描述:

当涉及从MongoDB使用Mongoose,Express和JSONStream(如果适用)发送文档集合时,我看到一些意外的性能数字。我想比较猫鼬发现与流。我曾预计更大的文档集合的速度会更快,但很惊讶地发现toArray变体的表现一直超越它们。我在想通配符可能是我使用JSONStream来表达响应。我简单的端点都低于:mongooose/mongodb流vs数组性能

// run this after connecting to mongoose 

var app = express(); 

var myModel = ...; // get mongoose model 
var myCollection = myModel.collection; 

// fetch 500 - use lean w/ mongoose 
var queryOpts = { lean : true, limit : 500 }; 

// 35.958 
app.get("/api/v1/stream", function(req, res) { 
    res.set('Content-Type', 'application/json'); 
    myModel.find({ }, null, queryOpts) 
    .stream().pipe(JSONStream.stringify()).pipe(res); 
}); 

// 36.228 
app.get("/api/v1/mongostream", function(req, res) { 
    res.set('Content-Type', 'application/json'); 
    myCollection.find({ }, queryOpts) 
    .stream().pipe(JSONStream.stringify()).pipe(res); 
}); 

// 23.399ms 
app.get("/api/v1/mongoarray", function(req, res) { 
    myCollection.find({ }, queryOpts) 
    .toArray(function(err, results) { 
     res.json(results); 
    }); 
}); 

// 23.908 
app.get("/api/v1/array", function(req, res) { 
    myModel.find({ }, null, queryOpts, function(err, results) { 
     res.json(results); 
    }); 
}); 

app.listen(4000); 

每个端点上面的评论表示由ab -k -n 1000 <endpoint>报告的平均请求时间。令我惊讶的是,将一个游标流传递给JSONStream以达到快速响应的速度比一次全部获取并发送要慢大约50%。我曾期望将数据流式传输更好。

有什么我正在做的,显然是错误的?我认为流应该更快?我错了吗?如果JSONStream是罪魁祸首,从光标流到表达响应的最佳方式是什么?如果我将它全部缓冲起来,是不是与其中一个数组变种一样?

注意DB服务器是mongo 2.4.x,mongo驱动程序是1.4.x.

更新我只定时读取/流部分而不是序列化方面。阵列变种和流媒体在阵列变体(14.9ms vs. 15.3ms)方面略有优势。下面是端点:

// No serialization - just timing 
// all are nearly the same - slight edge to 
// arrays 
app.get("/api/v2/stream", function(req, res) { 
    var start = process.hrtime(); 
    res.set('Content-Type', 'application/json'); 
    myModel.find({ }, null, queryOpts) 
    .stream().on('end', function() { 
     res.json(process.hrtime(start)); 
    }); 
}); 

app.get("/api/v2/mongostream", function(req, res) { 
    var start = process.hrtime(); 
    res.set('Content-Type', 'application/json'); 
    myCollection.find({ }, queryOpts) 
    .stream().on('end', function() { 
     res.json(process.hrtime(start)); 
    }); 
}); 

app.get("/api/v2/mongoarray", function(req, res) { 
    var start = process.hrtime(); 
    myCollection.find({ }, queryOpts) 
    .toArray(function(err, results) { 
     res.json(process.hrtime(start)); 
    }); 
}); 

app.get("/api/v2/array", function(req, res) { 
    var start = process.hrtime(); 
    myModel.find({ }, null, queryOpts, function(err, results) { 
     res.json(process.hrtime(start)); 
    }); 
}); 

更新2collection.stats()输出和collection.find({}).explain()如下:

> db.myCollection.stats(); 
{ 
    "ns" : "myDb.myCollection", 
    "count" : 1000, 
    "size" : 419264, 
    "avgObjSize" : 419.264, 
    "storageSize" : 847872, 
    "numExtents" : 4, 
    "nindexes" : 2, 
    "lastExtentSize" : 655360, 
    "paddingFactor" : 1, 
    "systemFlags" : 1, 
    "userFlags" : 0, 
    "totalIndexSize" : 98112, 
    "indexSizes" : { 
     "_id_" : 40880, 
     "_meta.tags_1" : 57232 
    }, 
    "ok" : 1 
} 
> db.myCollection.find({}).explain(); 
{ 
    "cursor" : "BasicCursor", 
    "isMultiKey" : false, 
    "n" : 1000, 
    "nscannedObjects" : 1000, 
    "nscanned" : 1000, 
    "nscannedObjectsAllPlans" : 1000, 
    "nscannedAllPlans" : 1000, 
    "scanAndOrder" : false, 
    "indexOnly" : false, 
    "nYields" : 0, 
    "nChunkSkips" : 0, 
    "millis" : 0, 
    "indexBounds" : { 

    }, 
    "server" : "LOCAL:27017" 
} 
+1

因此,在任何情况下,这是1000个对象,或约400K的数据,这是在Mongo的噪音领土中。在集合中有1亿个对象时,光标流变得有趣;与你现在在里面有什么关系,要么查询会很快,可能难以区分。 – 2014-10-19 16:53:21

这将是有益的,看看db.mycollection.stats的输出()和DB .mycollection.find({})。explain()来自mongo shell。

考虑到你所看到的性能数字,对于一个足够大的集合来说,一个非索引查询的冷树可能是所有时间都在的地方,而不是节点本身的任何开销。

+0

感谢您的回复!我用这些命令的输出更新了问题。我想Mongo会很有效地做这个搜索,因为我只是要求它能找到的第一批500个文件 - 没有订单或任何东西。 – Anon 2014-10-19 16:47:57