Nodejs 处理返回数十万行的 postgres 查询的最佳方式



我正在处理带有地图的数据仪表板。我创建了一个包含汽车位置的表,并且我有一个简单的查询。

选择 * 从表中,其中时间片 = ${时间片}

最初这很快,并且将必要的数据充分发送到前端,但是其他团队成员已经开始创建包含数百万条记录的表,现在前端的响应时间太慢了。在特定时间段,此查询现在返回超过 600k 条记录(在团队成员开始添加更多数据之前,它曾经最多返回 10k 左右)

我在表中添加了一个索引,将查询时间从 10-15 秒大幅缩短到 2 秒。但是,前端仍可能需要 1 分钟以上才能接收响应对象。我找不到任何关于提高速度的信息。

感谢您的任何帮助。

pg-cursor 是一个可能在这里有所帮助的工具。官方的 node-postgres 文档链接到此解决方案,并包含代码示例。

这将允许您分批获取查询(您确定的大小),并独立地对每个批次执行操作。以前的批次将被适当地进行垃圾回收(除非您有意保留对这些对象的引用)。

我在下面包含了我的实现的简化版本:


// how many rows to retrieve at a time
const BATCH_SIZE = 100;
const cursor = client.query(new Cursor('MY QUERY'));
// wrap the whole retrieval in a promise
function processResults() {
return new Promise((resolve, reject) => {
(function read() {
cursor.read(BATCH_SIZE, async (err, rows) => {
if (err) {
return reject(err);
}
// no more rows, so we're done!
if (!rows.length) {
return resolve();
}
// do something with those rows here...
// get the next batch
return read();
});
})();
});
}
const isComplete = await processResults();

gzip

我要尝试的第一件事是启用 gzip。如果您还没有这样做,这可能会将速度提高 10 倍,具体取决于您的数据结构/重复次数。您可以使用 koa-compress 表示 koa,也可以将压缩用于表达。

团体/装配工

接下来我会尝试看看是否有任何方法可以在将数据发送到客户端之前进行更多处理以对数据进行分组/合并/过滤。 例如,您是否需要每辆车的位置,或者您是否可以摆脱地图上每个网格方块中的汽车数量。然后,当用户放大时,您可以获取他们缩放到的区域的更详细数据。

缓存

如果这些都不是一种选择,那么你将考虑缓存和流媒体。

如果你有很多来自相同用户的重复访问,并且数据不经常更改,你可以使用类似localforage的东西将数据存储在客户端,然后在向服务器发出请求时,你可以只要求自给定日期以来已更改的记录。

如果确实必须,可以将数据流式传输到客户端。获取所有数据需要或多或少相同的时间,但他们会看到一些数据在进行时出现。@databases/pg 有一个返回行流的 db.stream 方法,你可以通过类似 newline-json 的东西来序列化它,然后将其通过管道传输到响应中。在客户端上,您可以在支持它们的浏览器上使用新的 fetch API 将数据作为流检索,然后您可以在每一行传入时对其进行解析。

最新更新