Node.js + PostgreSQL速度太慢

3

我有这段代码:

var pg = require('pg');
var QueryStream = require('pg-query-stream');
var constr = 'postgres://devel:1234@127.0.0.1/tcc';
var JSONStream = require('JSONStream');
var http = require('http');

pg.connect(constr, function(err, client, done) {
    if (err) {
        console.log('Erro ao conectar cliente.', err);
        process.exit(1);
    }

    sql = 'SELECT \
          pessoa.cod, \
          pessoa.nome, \
          pessoa.nasc, \
          cidade.nome AS cidade \
          FROM pessoa, cidade \
          WHERE cidade.cod IN (1, 2, 3);';

    http.createServer(function (req, resp) {
        resp.writeHead(200, { 'Content-Type': 'text/html; Charset=UTF-8' });
        var query = new QueryStream(sql);
        var stream = client.query(query);

        //stream.on('data', console.log);
        stream.on('end', function() {
            //done();
            resp.end()
        });
        stream.pipe(JSONStream.stringify()).pipe(resp);
    }).listen(8080, 'localhost');
});

当我在其中运行apache bench时,它只能每秒处理大约四个请求。如果我在php / apache或java / tomcat中运行相同的查询,则结果会快十倍。数据库有1000行。如果我将查询限制为大约十行,则node比php / java快两倍。
我做错了什么?
编辑:不久前,我在这里打开了一个问题:https://github.com/brianc/node-postgres/issues/653 我提供此链接,因为我在那里发布了我尝试过的其他代码变体。即使到目前为止有评论和提示,我也无法获得像样的速度。

3
你的所有客户端是否共享同一个数据库连接?如果是这样,你的请求可能会被串行化处理。我不确定这段代码是否正确利用了连接池。 - Brandon
@Brandon,是的,它们是。我也尝试了node-postgres文档中的这个例子,但结果差不多。 - Fernando Basso
1
@FernandoBasso,首先,我并不真正使用任何类型的SQL数据库,但从我所读到的关于querystream的内容来看,它只在内存中保留少量行。因此,我认为瓶颈是querystream,你可以尝试不使用querystream来解决问题。 - freeforall tousez
是的,你应该进行一个没有流式传输的基准测试,因为我猜在PHP / Apache中你不会流式传输查询结果。 - XCS
2
只是出于好奇 - 你没有将这两个表连接起来。这是有意为之吗? - Jayadevan
@Jayadevan 不是故意的。我非常关注我的主要问题,以至于没有注意到这一点。感谢您指出。 - Fernando Basso
4个回答

6
  • pg-query-stream 使用游标。
  • 它使用游标(加粗是为了强调)。
  • 你可以阅读代码并更改 batchSize 以更好地适应你的需求。

对于那些不知道什么是游标的人,简单来说,它们是为了保持内存占用小而不将整个表读入内存所做出的一种权衡。但是,如果你每次获取 100 行,而你有 1000 条结果,那么就需要进行 1000 / 100 次往返操作;因此,可能比不使用游标的解决方案慢 10x

如果你知道需要多少行数据,请在查询中添加 limit 并更改每次返回的行数,以最小化往返次数。


1
@giladmayani,您是在说答案的某个部分很粗鲁吗?您能详细说明哪个部分吗?我会进行修正。 - dnozay
1
我认为你多次重复“它使用游标”这一部分是粗鲁的,听起来很讽刺。 - gilad905
2
你误将强调当作粗鲁/讽刺;但我修改了答案。 - dnozay

1
据我所知,从这段代码中可以看出,您创建了一个到PostgreSQL的单个连接,并将所有内容排队通过它传输。 pg模块允许这样做,具体请参见此处: https://github.com/brianc/node-postgres/wiki/Queryqueue 如果您想要真正的性能,每个HTTP请求都应该从池中获取连接,使用它,释放它,并确保始终释放(例如适当的异常处理),否则一旦池完全耗尽,您的服务器将会崩溃。
一旦您到达那里,就可以调整连接池参数并测量性能。

0

看起来你在等待服务器创建完成之后才能转发请求。尝试将http.createServer移动到调用外部。如果你只想在请求中使用http服务器,可以尝试使调用异步。


Node.js是异步的,如果我没记错的话。另外,将http.createServer移出pg.connect会导致它无法工作,因为它使用了从pg.connect获取的变量名client - freeforall tousez
@freeforalltousez 默认情况下它是异步的,但是调用内部的代码需要使用异步包。截至目前为止,代码读取了以下步骤:1)连接到pg,2)查询,3)创建服务器,管道流。 - Stephen Punwasi
我原以为这段代码的功能是:1)连接到pg,2)创建服务器并监听端口,3)当客户端(浏览器)连接到服务器时进行查询,然后将数据流传输。 - freeforall tousez

0
也许你应该设置http.agent.maxSockets值,尝试这样做:
var http = require('http');
http.agent.maxSockets = {{number}};

默认的最大套接字数是5


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接