14

我有桌子

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 甚至更新的版本有一些特性?我已经搜索过,但没有找到任何东西。

4

2 回答 2

31

OFFSET的总是会很慢。Postgres 必须对所有行进行排序并将可见行数到您的偏移量。要直接跳过所有先前的行,您可以将索引添加row_number到表中(或创建一个MATERIALIZED VIEW包含 said 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_x)。或者如果向后导航,则从第一个开始id_xDESCASC

您已经拥有的索引支持比较行值 - 该功能符合 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构造:

特别注意两点

  1. 子句中的ROWWHERE不能用单独的成员字段替换。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
    

    ...它不能很好地与索引一起使用,并且对于更多列变得越来越复杂。

    显然,对于单个列来说很简单。这就是我一开始提到的特殊情况。

  2. 该技术不适用于以下混合方向ORDER BY

    ORDER  BY vote ASC, id DESC
    

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

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

有关的:

请特别注意 Markus Winand 的演示文稿,我链接到:

于 2015-12-15T13:57:44.917 回答
-4

您是否尝试过分区表?

易于管理、改进的可扩展性和可用性以及减少阻塞是分区表的常见原因。提高查询性能不是采用分区的理由,尽管在某些情况下它可能是有益的副作用。在性能方面,确保您的实施计划包括对查询性能的审查非常重要。确认您的索引在表分区后继续适当地支持您的查询,并验证使用聚集和非聚集索引的查询是否受益于适用的分区消除。

http://sqlperformance.com/2013/09/sql-indexes/partitioning-benefits

于 2015-12-05T20:40:49.030 回答