postgresql 使用OFFSET优化大型表的查询

6tqwzwtp  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(2)|浏览(259)

我有table

create table big_table (
id serial primary key,
-- other columns here
vote int
);

这个表很大,大约有7000万行,我需要查询:

SELECT * FROM big_table
ORDER BY vote [ASC|DESC], id [ASC|DESC]
OFFSET x LIMIT n  -- I need this for pagination

正如您所知,当x是一个很大的数字时,这样的查询非常慢。
为了优化性能,我添加了索引:

create index vote_order_asc on big_table (vote asc, id asc);

和/或

create index vote_order_desc on big_table (vote desc, id desc);

EXPLAIN显示上面的SELECT查询使用了这些索引,但是它非常慢,偏移量很大。
如何在大表中使用OFFSET优化查询?也许PostgreSQL 9.5或更新版本有一些功能?我找过了但什么也没找到。

oxosxuxt

oxosxuxt1#

一个大的OFFSET总是很慢。Postgres必须对所有行进行排序,并将 * 可见 * 的行计数到偏移量。要直接跳过前面的所有行直接,可以在表中添加索引row_number(或创建MATERIALIZED VIEW,包括row_number),然后使用WHERE row_number > x而不是OFFSET x
然而,这种方法仅适用于只读(或大部分)数据。对于可以 * 并发 * 更改的表数据,实现相同的方法更具挑战性。你需要从定义你想要的行为开始 * 精确
我建议一种不同的方法,有时称为
“键集分页”**:

SELECT *
FROM   big_table
WHERE  (vote, id) > (vote_x, id_x)  -- ROW values
ORDER  BY vote, id  -- needs to be deterministic
LIMIT  n;

其中vote_xid_x来自***上一页***的 * 最后 * 行(DESCASC)。或从 * 第一个 *,如果导航 * 向后 *。
比较行值由您已有的索引支持-这是一个符合ISO SQL标准的功能,但并非所有RDBMS都支持它。

CREATE INDEX vote_order_asc ON big_table (vote, id);

或降序:

SELECT *
FROM   big_table
WHERE  (vote, id) < (vote_x, id_x)  -- ROW values
ORDER  BY vote DESC, id DESC
LIMIT  n;

可以使用相同的索引。
我建议你声明你的列NOT NULL或者熟悉NULLS FIRST|LAST的构造:

  • 按ASC列排序,但先按NULL值排序?

注意两件事特别:

  1. WHERE子句中的ROW值不能用分开的成员字段替换。WHERE (vote, id) > (vote_x, id_x)***不能***替换为:
WHERE  vote >= vote_x
AND    id   > id_x

这将排除 * 所有 * 行id <= id_x,而我们只想为同一个投票而不是下一个投票做这件事。正确的翻译应该是:

WHERE (vote = vote_x AND id > id_x) OR vote > vote_x

...这并不能很好地与索引一起工作,并且对于更多的列来说变得越来越复杂。
显然,对于一个 * 单 * 列来说很简单。这就是我在一开始提到的特殊情况。
1.该技术不适用于ORDER BY中的混合方向,如:

ORDER  BY vote ASC, id DESC

至少我想不出一种通用的方法来有效地实现这个。如果这两列中至少有一列是数值类型,则可以在(vote, (id * -1))上使用一个带有倒排值的函数索引-并在ORDER BY中使用相同的表达式:

ORDER  BY vote ASC, (id * -1) ASC

相关内容:

请特别注意Markus Winand的演讲,我链接到:

wyyhbhjk

wyyhbhjk2#

你试过把table分开吗?
易于管理、改进的可伸缩性和可用性以及减少阻塞是划分表的常见原因。提高查询性能并不是使用分区的理由,尽管在某些情况下这可能是一个有益的副作用。在性能方面,确保实现计划包括查询性能的审查非常重要。确认在表分区后,索引继续适当地支持查询,并验证使用聚集索引和非聚集索引的查询是否受益于分区消除(如果适用)。
http://sqlperformance.com/2013/09/sql-indexes/partitioning-benefits

相关问题