我在PostgreSQL中创建了一个按received
列分区的表(见这里)。让我们举一个玩具的例子:
CREATE TABLE measurement (
received timestamp without timezone PRIMARY KEY,
city_id int not null,
peaktemp int,
unitsales int
);
几年来,我每个月都创建了一个分区(measurement_y2012m01
... measurement_y2016m03
)。
我注意到postgresql不知道分区的顺序,因此对于如下所示的查询:
select * from measurement where ... order by received desc limit 1000;
PostgreSQL 对所有分区执行索引扫描,即使前 1000 个结果很可能位于最新的分区(或前两个或三个)中。
您知道如何利用分区进行此类查询吗?我想强调的是,where
子句可能会有所不同,我不想对其进行硬编码。
第一个想法是以正确的顺序迭代分区,直到获取 1000 条记录或访问所有分区。但是如何以灵活的方式实现它呢?我想避免在应用程序中实现上述迭代,但我不介意应用程序是否需要调用存储过程。
提前感谢您的帮助!
格热戈兹
如果您真的不知道要扫描多少个分区才能在输出中获得所需的 1000 行,则可以在存储过程中构建结果集,并获取遍历分区的结果,直到满足限制条件。
从最新的分区开始将是明智之举。
select * from measurement_y2016m03 where ... order by received desc limit 1000;
您可以将即时结果集存储在记录中并对其发出计数,并动态更改下一个扫描分区的限制,这样,例如,如果您在第一个分区中获取870
行,则可以使用 limit 130
构建第二个查询,然后再次执行计数,如果它仍然不满足1000
行条件,则增加计数器。
为什么Postgres在计划期间不知道何时停止?
计划程序不知道需要多少个分区才能满足您的LIMIT
子句。因此,它必须通过附加每个分区的结果来对整个集进行排序,然后执行限制(除非它在运行时已经满足此条件)。在 SQL 语句中执行此操作的唯一方法是将查找限制为仅几个分区 - 但您可能并非如此。此外,如果您在查找期间点击磁盘,增加work_mem
设置可能会加快速度。
基调
另外,要记住的一件事是,当您设置分区时,您应该有一个最常访问的分区的降序。这将加快您的插入速度,因为 Postgres 会逐个检查条件,并在满足条件的第一个停止。
您可以猜测满足查询的received
范围,而不是迭代分区并扩展它,直到获得所需的行数。将范围添加到WHERE
将排除不必要的分区(假设设置了排除约束)。
编辑
正确,这就是我的意思(可以更好地表达)。
简单性似乎是一个非常合理的优势。无论哪种方式,我都不认为性能有什么不同。如果您大部分时间猜测合理地接近所需范围,这实际上可能会更有效,但可能不会产生显着差异。
它也更灵活一些,因为您不依赖于查询代码中的特定分区方案。