Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 具有大量查询的节点postgres_Node.js_Postgresql_Node Postgres - Fatal编程技术网

Node.js 具有大量查询的节点postgres

Node.js 具有大量查询的节点postgres,node.js,postgresql,node-postgres,Node.js,Postgresql,Node Postgres,我刚刚开始使用node.js和postgres,使用node-postgres。我尝试做的一件事是编写一个简短的js来填充我的数据库,使用一个包含大约200000个条目的文件 我注意到过了一段时间(不到10秒),我开始收到“错误:连接终止”。我不确定这是我如何使用节点postgres的问题,还是因为我在滥发postgres 无论如何,这里有一个简单的代码显示了这种行为: var pg = require('pg'); var connectionString = "postgres://xxxx

我刚刚开始使用node.js和postgres,使用node-postgres。我尝试做的一件事是编写一个简短的js来填充我的数据库,使用一个包含大约200000个条目的文件

我注意到过了一段时间(不到10秒),我开始收到“错误:连接终止”。我不确定这是我如何使用节点postgres的问题,还是因为我在滥发postgres

无论如何,这里有一个简单的代码显示了这种行为:

var pg = require('pg');
var connectionString = "postgres://xxxx:xxxx@localhost/xxxx";

pg.connect(connectionString, function(err,client,done){
  if(err) {
    return console.error('could not connect to postgres', err);
  }

  client.query("DROP TABLE IF EXISTS testDB");
  client.query("CREATE TABLE IF NOT EXISTS testDB (id int, first int, second int)");
  done();

  for (i = 0; i < 1000000; i++){
    client.query("INSERT INTO testDB VALUES (" + i.toString() + "," + (1000000-i).toString() + "," + (-i).toString() + ")",   function(err,result){
      if (err) {
         return console.error('Error inserting query', err);
      }
      done();
    });
  }
});
var pg=require('pg');
变量连接字符串=”postgres://xxxx:xxxx@本地主机/xxxx”;
pg.connect(连接字符串、函数(错误、客户端、完成){
如果(错误){
返回控制台。错误('无法连接到postgres',错误);
}
query(“如果存在testDB,则删除表”);
query(“创建表,如果不存在testDB(id int,first int,second int)”;
完成();
对于(i=0;i<1000000;i++){
query(“插入testDB值(“+i.toString()+”,“+(1000000-i).toString()+”,“+(-i.toString()+”),函数(err,result){
如果(错误){
返回控制台.error('插入查询时出错',err);
}
完成();
});
}
});
在大约18000-20000次查询后,它会失败。这是使用client.query的错误方法吗?我尝试更改默认的客户机号码,但似乎没有帮助

client.connect()似乎也没有什么帮助,但那是因为我有太多的客户端,所以我肯定认为客户端池是一种方法


谢谢你的帮助

我猜您正在达到最大池大小。由于
client.query
是异步的,所以在返回所有可用的连接之前,都会先使用它们

默认池大小为10。请点击此处:

通过设置
pg.defaults.poolSize
,可以增加默认池大小:

pg.defaults.poolSize = 20;

更新:释放连接后执行另一个查询

var pg = require('pg');
var connectionString = "postgres://xxxx:xxxx@localhost/xxxx";
var MAX_POOL_SIZE = 25;

pg.defaults.poolSize = MAX_POOL_SIZE;
pg.connect(connectionString, function(err,client,done){
  if(err) {
    return console.error('could not connect to postgres', err);
  }

  var release = function() {
    done();
    i++;
    if(i < 1000000)
      insertQ();
  };

  var insertQ = function() {
    client.query("INSERT INTO testDB VALUES (" + i.toString() + "," + (1000000-i).toString() + "," + (-i).toString() + ")",        function(err,result){
      if (err) {
         return console.error('Error inserting query', err);
      }
      release();
    });
  };

  client.query("DROP TABLE IF EXISTS testDB");
  client.query("CREATE TABLE IF NOT EXISTS testDB (id int, first int,    second int)");
  done();

  for (i = 0; i < MAX_POOL_SIZE; i++){
    insertQ();
  }
});
var pg=require('pg');
变量连接字符串=”postgres://xxxx:xxxx@本地主机/xxxx”;
var MAX_POOL_SIZE=25;
pg.defaults.poolSize=最大池大小;
pg.connect(连接字符串、函数(错误、客户端、完成){
如果(错误){
返回控制台。错误('无法连接到postgres',错误);
}
var release=function(){
完成();
i++;
如果(i<1000000)
insertQ();
};
var insertQ=函数(){
query(“插入testDB值(“+i.toString()+”,“+(1000000-i).toString()+”,“+(-i.toString()+”),函数(err,result){
如果(错误){
返回控制台.error('插入查询时出错',err);
}
释放();
});
};
query(“如果存在testDB,则删除表”);
query(“创建表,如果不存在testDB(id int,first int,second int)”;
完成();
对于(i=0;i

其基本思想是,由于您正在以相对较小的连接池大小将大量查询排队,因此您将达到最大池大小。这里,我们仅在释放现有连接后进行新查询。

更新

此后,这一答案被本文取代,它代表了最新的方法


为了复制您的场景,我使用了库,并且我可以确认,正面尝试永远不会奏效,无论您使用哪个库,重要的是方法

下面是一种改进的方法,我们将插入划分为块,然后在事务中执行每个块,这就是负载平衡(也称为节流):

函数插入记录(N){
返回db.tx(函数(ctx){
var查询=[];
对于(变量i=1;i=9){
回报承诺。决心(“成功”);
}否则{
返回insertAll(++idx);
}
},功能(原因){
退回承诺。拒绝(理由);
});
}
insertAll()
.then(功能(数据){
控制台日志(数据);
},功能(原因){
控制台日志(原因);
})
.done(函数(){
pgp.end();
});
这在大约4分钟内产生了1000000条记录,在前3次事务处理后,速度大大减慢。我使用的是节点JS 0.10.38(64位),它消耗了大约340MB的内存。这样我们插入了100000条记录,连续10次

如果我们也这样做,这次只在100个事务中插入10000条记录,同样的1000000条记录只需1m25s就可以添加,速度不会减慢,节点JS消耗了大约100MB的内存,这告诉我们,像这样划分数据是一个非常好的主意

无论您使用哪个库,方法都应该相同:

  • 将插入内容划分/限制为多个事务
  • 将单笔交易中的插入列表保持在10000条记录左右
  • 在同步链中执行所有事务
  • 在每个事务提交后释放回池的连接
  • 如果你违反了这些规则,你肯定会有麻烦。例如,如果您违反规则3,您的NodeJS进程很可能会很快耗尽内存并抛出错误。我的例子中的规则4是由图书馆提供的

    如果您遵循这种模式,就不必为连接池设置而烦恼

    更新1

    更高版本的完全支持此类场景,如下所示:

    function factory(index) {
        if (index < 1000000) {
            return this.query('insert into test(name) values($1)', 'name-' + index);
        }
    }
    
    db.tx(function () {
        return this.batch([
            this.none('drop table if exists test'),
            this.none('create table test(id serial, name text)'),
            this.sequence(factory), // key method
            this.one('select count(*) from test')
        ]);
    })
        .then(function (data) {
            console.log("COUNT:", data[3].count);
        })
        .catch(function (error) {
            console.log("ERROR:", error);
        });
    
    功能工厂(索引){
    如果(索引<1000000){
    返回此.query('insert into test(name)values($1)','name-'+索引);
    }
    }
    db.tx(函数(){
    退回此批([
    this.none('drop table if exists test'),
    this.none('创建表测试(id序列,名称文本)'),
    this.sequence(factory),//键方法
    这个.one('select count(*)from test')
    ]);
    })
    .then(功能(数据){
    log(“计数:”,数据[3]。计数);
    })
    .catch(函数(错误){
    日志(“错误:”,错误);
    });
    
    <
    function factory(index) {
        if (index < 1000000) {
            return this.query('insert into test(name) values($1)', 'name-' + index);
        }
    }
    
    db.tx(function () {
        return this.sequence(factory);
    })
        .then(function (data) {
            // success;
        })
        .catch(function (error) {
            // error;
        });