PostgreSQL:保留排序顺序/临时索引/分页

时间:2013-06-05 14:06:00

标签: sql postgresql pagination

我正在使用PostgreSQL,我打算分页。目标表包含1M +行。原则上,这是直截了当的

SELECT * FROM myTable ORDER BY orderCol LIMIT <pageSize> OFFSET <offset>;

现在,当orderCol被索引时这很快,但是当orderCol没有索引时,这个数字会慢一个数量级。显然,在最坏的情况下,dbms被迫执行全表扫描,并且必须为每个请求的页面排序数据。

[编辑:更具体地说,orderCol可能会发生变化,即在运行时确定。{/ p>

[ Edit2:索引orderCol提高排序性能的一般假设似乎是错误的。如果我向orderCol添加索引,查询时间会增加约70%。]

一个明显的解决方案是根据需要使用适当的索引创建临时表,并使用适当的数据填充表(...我认为)。但这复制了所有数据。

有没有办法可以“保留”请求之间的排序顺序?或者创建一个临时索引?

非常感谢你提前给出答案。

3 个答案:

答案 0 :(得分:1)

好的,这是我提出的一个解决方案。

问题实际上是确定性行寻址和关系模型不兼容。我基本上要做的是告诉数据库下一步要看哪里。但由于请求彼此独立,并且我们无法对表的物理结构做出任何假设,因此解决行的唯一方法是使用唯一的列值。

因此以下解决方案:

CREATE TEMPORARY TABLE orderTable( id int, rank int );
CREATE INDEX orderIdx ON orderTable( rank );
INSERT INTO orderTable (
  select id, row_number() over (order by orderCol) as rank 
  from myTable ORDER BY orderCol
);

现在,我可以按如下方式获取页面:

SELECT myTable.id, orderCol 
FROM myTable JOIN orderTable ON myTable.id=orderTable.id 
WHERE rank >= <lower> AND rank <= <upper>;

乍一看这听起来很疯狂,但是对于大约128的页面大小,与在myTable上使用带有索引(和聚类)的orderCol相比,它将查询时间减少了大约一个数量级。

答案 1 :(得分:1)

你遇到了几个问题:

是的,排序未编制索引的列

您可能真的想索引所有可排序的列配置,至少是那些由您的应用程序经常排序的列配置。有关该主题的一些有趣见解in this blog

OFFSET很慢

即使您有索引,跳转到高页码也很慢,因为您必须遍历整个索引才能进行OFFSET计数。试着看看你是否可以使用"seek method"

搜索方法实际上跳转到上一页的最后一条记录后的第一条记录,例如

SELECT * 
FROM myTable 
WHERE orderCol > :lastValueforOrderCol
ORDER BY orderCol
LIMIT <pageSize>;

现在您不再按偏移量访问记录,但通过使用谓词,索引所有符合条件的orderCols是必不可少的。

请注意,此方法不允许您跳转到固定的序号位置,例如OFFSET。它的行为更像Twitter的“后续推文”的延迟加载。这可能是也可能不是。

注意,“搜索方法”也称为keyset paging

全表扫描可以比索引扫描更快

由于您没有任何谓词,执行哑全表扫描并在内存中执行排序可能确实更快,而不是加载所有索引b树节点(可能分散在磁盘上)以跳过行。一旦添加选择性谓词,这种观察可能会被逆转。

我很惊讶,PostgreSQL的优化器不会自动选择全表扫描。

答案 2 :(得分:0)

什么阻止你只是索引这个列?

我有一个类似的问题,但对于一个20GB / 40M +行表,有很多“where”条件。数据是静态的,所以我让DW Server运行一个每日脚本,它只提取相关数据并创建了一个150k表。

更新

  

编辑:更具体地说,orderCol可能会改变,即在运行时确定

你的意思是,每当有人运行查询时,order列中的值都会改变(或者列可以是不同的,column1,colume2,......)?

查看物化视图。 http://wiki.postgresql.org/wiki/Materialized_Views

您可以在此查询上创建一个视图,然后从该视图中运行所有查询(并通过脚本每隔x min /小时/天删除它们)。比临时表更容易处理。

除此之外,还有一些技巧取决于详细的用例,但没有开箱即用的解决方案