在大表

时间:2015-12-05 20:30:40

标签: sql postgresql pagination sql-order-by postgresql-9.5

我有桌子

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甚至更新版本都有一些功能?我搜索过但没找到任何东西。

2 个答案:

答案 0 :(得分:21)

OFFSET总是很慢。 Postgres必须订购所有行并将可见计算到您的偏移量。要直接跳过 之前的所有行,您可以在表格中添加一个已编入索引的row_number(或创建包含所述row_number的{​​{3}}并使用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来自 上一页 last 行(适用于{{}} 1}}和DESC)。或者从第一个开始向后

您已经拥有的索引支持比较行值 - 这是一个符合ANSI SQL的功能,但不是每个RDBMS都支持它。

ASC

或者按降序排列:

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构造:

特别注意两件事

  1. NULLS FIRST|LAST子句中的ROW值不能替换为分隔的成员字段。 WHERE 无法 替换为:

    WHERE (vote, id) > (vote_x, id_x)

    这将排除带有WHERE vote >= vote_x AND id > id_x所有行,而我们只希望为同一投票而不是下一行投票。正确的翻译是:

    id <= id_x

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

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

  2. 该技术不适用于WHERE (vote = vote_x AND id > id_x) OR vote > vote_x 中的混合方向,如:

    ORDER BY

    至少我不能想到一种泛型方式来有效地实现它。如果两列中至少有一列是数字类型,则可以使用ORDER BY vote ASC, id DESC 上具有反转值的功能索引 - 并在(vote, (id * -1))中使用相同的表达式:

    ORDER BY
  3. 相关:

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

答案 1 :(得分:-4)

你有没有尝试过分桌?

  

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

     

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