Javascript 节点中的RXJS PostgreSQL背压
原始标题:如何降低javascript中PgSQL结果行流的速度 我在使用RXJS(5.4.0)和PostgreSQL(驱动程序“pg”:“6.1.4”)的nodejs v4.5.0中遇到内存不足问题 我手动创建一个可观察的PgSQL行,如下所示:Javascript 节点中的RXJS PostgreSQL背压,javascript,node.js,postgresql,typescript,rxjs,Javascript,Node.js,Postgresql,Typescript,Rxjs,原始标题:如何降低javascript中PgSQL结果行流的速度 我在使用RXJS(5.4.0)和PostgreSQL(驱动程序“pg”:“6.1.4”)的nodejs v4.5.0中遇到内存不足问题 我手动创建一个可观察的PgSQL行,如下所示: return Rx.Observable.create((subscriber) => { pool.connect().then((client: pg.Client) => { const stream:any
return Rx.Observable.create((subscriber) => {
pool.connect().then((client: pg.Client) => {
const stream:any = client.query(query.toParam());
stream.on('row', (row) => {
subscriber.next(row);
});
stream.on('end', () => {
subscriber.complete();
client.release();
});
});
});
然后我将一些操作符附加到rx可观测对象上,并进行一些处理。
请注意,从数据库返回的行有点重
调查使我得出一个结论:
数据库中的行返回的速度比处理它们的速度快得多。必须为这些繁重的数据保留内存才能等待处理,这会导致内存不足问题:
致命错误:调用和重试上次分配失败-进程内存不足
中止陷阱:6
我在PostgreSQL驱动程序上看不到任何暂停流的选项。有什么想法可以解决这个问题吗?如果您使用的是同一位作者的,那么应该是比较直截了当的:
return Rx.Observable.defer(() => pg.connect())
.flatMap(client => {
const cursor = client.query(new Cursor('SELECT * FROM some_table WHERE prop > $1', [100]))
const observableCursor = Rx.Observable.bindNodeCallback(cursor.read.bind(cursor));
// Get the first 100 items
observableCursor(100)
.map(processRows)
// This will only emit after the first one completes
// and will recursively call this for each result
.expand(_ =>
observableCursor(100)
.map(processRows)
)
// Unsubscribes once we don't get any more results
.takeWhile(rows => rows.length > 0)
});
我试图写@paulpdaniels solution建议的尽可能多的可读性,但我不确定这是否真的是反应式风格 我还有一个不同的处理函数,它取决于上下文变量。我喜欢有一个架构,可以方便地使用不同的rxjs操作符链,这取决于上下文条件并隐藏游标。读取逻辑,但我担心这是不可能的 当我显式地告诉数据库携带下一批数据(cursor.read)时,必须有一个位置,而且必须是在我从大量数据中释放内存后的位置 以下解决方案为typescript:
const db = require('./libs/db.js');
import * as Cursor from 'pg-cursor';
import * as pg from 'pg';
import * as Rx from 'rxjs';
let cursor, readHandler;
const source = Rx.Observable.create((subscriber) => {
db.getClient().then((client: pg.Client) => {
cursor = client.query(new Cursor('SELECT * FROM some_table WHERE prop > $1', [100]));
readHandler = function (err, rowsBulk) {
if (err) {
subscriber.error(err);
return client.release();
}
if (!rowsBulk.length) {
subscriber.complete();
return client.release();
}
subscriber.next(rowsBulk);
};
}).then(() => {
// fetch first 100 records
cursor.read(100, readHandler);
});
});
source.flatMap((item) => {
return new Promise((resolve) => {
console.log('processing batch of items');
setTimeout(() => { // timeout simulates processing
item = null;
console.log('release memory');
resolve({});
}, 5000);
});
}).map(() => {
// fetch every next 100 records
console.log('allocate new memory');
cursor.read(100, readHandler);
return '.';
}).subscribe(console.log, (err) => {
console.log('Error occurred');
console.error(err);
});
原始查询得到的列是否超出需要?有时,在大型结果集上使用“select*”是个坏主意。不幸的是,在SQL查询级别没有太多的优化空间。其中一列包含重要数据,这是最重要的一列。您必须对数据进行分页读取,仅此而已。使用
LIMIT
和OFFSET
进行此操作。在获取下一部分之前,使用光标并仅获取少量结果。CUROSR是PL/pgSQL功能,但在我的情况下,我需要将数据检索到javascript上下文中。在您的问题中,可能会扩展到“取决于上下文变量的不同处理函数”。我可以更新我的答案,但前提是你给出更具体的答案。我已经更新了标题并标记了你的信息。我同意将上下文对象作为参数传递到处理函数中。