sql - 在 postgresql 中对一个非常大的表进行分页和过滤(键集分页?)

标签 sql node.js postgresql

我有一个科学数据库,目前有 4,300,000 条记录。它是一个科学数据库,由 API 提供支持。到 2020 年 6 月,我可能会有大约 100,000,000 条记录。

这是表“输出”的布局:

ID   | sensor_ID    | speed    | velocity | direction
-----------------------------------------------------
1    | 1            | 10       | 1        | up
2    | 2            | 12       | 2        | up
3    | 2            | 11.5     | 1.5      | down
4    | 1            | 9.5      | 0.8      | down
5    | 3            | 11       | 0.75     | up
...

顺便说一句,这是虚拟数据。但是输出是一个有 5 列的表:ID、sensor_ID、速度、速度和方向。

我想要实现的是 体面的 分页和过滤方法。我想创建一个网站(在 nodejs 中),其中将显示 +4,000,000 条记录(目前),每页 10,000 条记录。我还希望能够过滤 sensor_ID、速度、速度或方向。

现在,我有这个用于选择特定行的查询:
SELECT * FROM output ORDER BY ID DESC OFFSET 0 LIMIT 10000 // first 10,000 rows

SELECT * FROM output ORDER BY ID DESC OFFSET 10000 LIMIT 10000 // next 10,000 rows

...

我正在寻找有关创建合适的分页方法的一些信息/提示。 就目前 而言,按照我的方式,它仍然很快,但我认为当我们达到 +50,000,000 条记录时,速度会慢很多。

首先,我找到了这个页面: https://www.citusdata.com/blog/2016/03/30/five-ways-to-paginate/ 。我对 键集 分页感兴趣。但老实说,我不知道如何开始。

认为 我必须做的:

在 ID 字段上创建索引:
CREATE UNIQUE INDEX index_id ON output USING btree (ID)

我还找到了这个页面: https://leopard.in.ua/2014/10/11/postgresql-paginattion 。当您向下滚动到“改进 #2:寻求方法”时,您可以看到他们删除了 OFFSET 子句,并使用了 WHERE 子句。我还看到他们在查询中使用了 最后一个插入 ID :
SELECT * FROM output WHERE ID < <last_insert_id_here> ORDER BY ID DESC LIMIT 10000

我不完全理解这一点。对于第一页,我需要最后一个插入 ID。然后我获取 10,000 条最新记录。但在那之后,要获得第二页,我不需要最后一个插入 ID,我需要第 10,000 个最后插入 ID(我猜)。

有人可以快速给我一个关于分页和过滤的很好的解释。

我正在使用的东西:
- PostgreSQL
- pgadmin(用于数据库管理)
- node.js(最新版本)

谢谢大家!并有一个美好的2020年!

编辑 1: 我不知道,但是 massJS ( https://massivejs.org/ ) 会不会很好用?我应该在所有查询上使用它,还是只在分页查询上使用它?

编辑 2: 我想我已经弄明白了一点(如果我错了,请纠正我)。

假设我有 100,000 条记录:

1) 获取最后插入的ID

2) 使用这个最后插入的 ID 来获取最后 10,000 条记录
SELECT * FROM output WHERE ID < 100000 ORDER BY ID DESC LIMIT 10000 // last insert ID is here 100,000 because I have 100,000 records

3) 显示 10,000 条记录,但还要保存 10,000 条记录的插入 ID 以供下次查询使用

4) 使用新的最后插入 id 获取接下来的 10,000 条记录
SELECT * FROM output WHERE ID < 90000 ORDER BY ID DESC LIMIT 10000 // 90,000 is the very last insert id - 10,000

5) ...

这样对吗?

最佳答案

这是我处理这个的方法。对于我获取的第一页,我使用

SELECT id, col, col, col 
  FROM output 
 ORDER BY id DESC
 LIMIT 10000

然后,在我的客户端程序 (node.js) 中,我从结果集的最后一行捕获 id 值。当我需要下一页时,我会这样做。
 SELECT id, col, col, col
   FROM output
  WHERE id < my_captured_id_value
  ORDER BY id DESC

这利用了索引。即使您从表中删除了一些行,它也能正常工作。

顺便说一句,如果您的第一个分页页面具有最大的 id,您可能需要一个降序索引。 CREATE UNIQUE INDEX index_id ON output USING btree (ID DESC)

专业提示 SELECT * 对大型数据库的性能有害。始终列出您实际需要的列。

关于sql - 在 postgresql 中对一个非常大的表进行分页和过滤(键集分页?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59619956/

相关文章:

sql - 在 SQL 中无约束地向表添加新列

PostgreSQL:错误:42601:返回 "record"的函数需要列定义列表

sql - 动态调整一个变量保存多个值的存储过程

mysql - 连接三个表或使用 IN 嵌套查询

sql - 如何从sql数据库表列中删除特定字符?

javascript - express 无法查找 View

node.js - HttpClient 订阅的响应 header 未定义

javascript - NestJS + TypeORM - 连接到 mysql 和 mongodb 时出错

java - 连接到 Postgresql 错误

sql - 如何连接上个月缺少行的两个表?