Postgres多分区表的高效查询

Posted

技术标签:

【中文标题】Postgres多分区表的高效查询【英文标题】:Efficient querying of multi-partition Postgres table 【发布时间】:2010-02-10 12:39:33 【问题描述】:

我刚刚重组了我的数据库以在 Postgres 8.2 中使用 partitioning。现在我的查询性能有问题:

SELECT *
FROM my_table
WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11'
ORDER BY id DESC
LIMIT 100;

表中有 4500 万行。在分区之前,这将使用反向索引扫描并在达到限制时立即停止。

分区后(在 time_stamp 范围内),Postgres 对主表和相关分区进行全索引扫描并合并结果,对它们进行排序,然后应用限制。这需要的时间太长了。

我可以解决它:

SELECT * FROM (
  SELECT *
  FROM my_table_part_a
  WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11'
  ORDER BY id DESC
  LIMIT 100) t
UNION ALL
SELECT * FROM (
  SELECT *
  FROM my_table_part_b
  WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11'
  ORDER BY id DESC
  LIMIT 100) t
UNION ALL
  ... and so on ...
ORDER BY id DESC
LIMIT 100

这运行得很快。时间戳超出范围的分区甚至不包含在查询计划中。

我的问题是:我可以在 Postgres 8.2 中使用一些提示或语法来防止查询计划程序扫描整个表,但仍然使用仅引用主表的简单语法?

基本上,我是否可以避免在碰巧当前定义的每个分区上动态构建大型 UNION 查询的痛苦?

编辑:我启用了约束排除(感谢@Vinko Vrsalovic)

【问题讨论】:

【参考方案1】:

您是否尝试过约束排除(您链接到的文档中的第 5.9.4 节)

约束排除是一个查询 改进的优化技术 分区表的性能 以描述的方式定义 多于。举个例子:

 SET constraint_exclusion = on; 
 SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01'; 

没有 约束排除,上述查询 将扫描每个分区 测量表。有约束 启用排除,规划器将 检查每个约束 划分并尝试证明 不需要扫描分区,因为 它不能包含任何会议的行 查询的 WHERE 子句。当。。。的时候 计划者可以证明这一点,它不包括 查询计划中的分区。

您可以使用 EXPLAIN 命令 显示计划之间的差异 使用 constraint_exclusion 和一个 计划关闭它。

【讨论】:

是的,我打开了约束排除。不幸的是,主表(始终为空)始终包含在查询中,因为无法对其应用 CHECK 约束(至少在 8.2 中)。这意味着查询中始终至少涉及两个表【参考方案2】:

我有一个类似的问题,我可以通过在 WHERE 中转换条件来解决。 EG:(假设time_stamp列是timestamptz类型)

WHERE time_stamp >= '2010-02-10'::timestamptz and time_stamp < '2010-02-11'::timestamptz

另外,请确保表上的 CHECK 条件以相同的方式定义... 例如: 检查(time_stamp

【讨论】:

【参考方案3】:

我遇到了同样的问题,在我的情况下归结为两个原因:

    我已经为 timestamp WITH time zone 类型的列建立了索引,并且此列的分区约束为 timestamp WITHOUT time zone

    需要修复所有子表的约束ANALYZE

编辑:另外一点知识 - 重要的是要记住约束排除(它允许 PG 根据您的分区标准跳过扫描某些表)不起作用,引用:non-immutable function such as CURRENT_TIMESTAMP

我收到了CURRENT_DATE 的请求,这是我的问题的一部分。

【讨论】:

以上是关于Postgres多分区表的高效查询的主要内容,如果未能解决你的问题,请参考以下文章

postgres 在 current_date 查询分区表

PostgreSQL 是不是并行查询分区?

Postgres 分区性能调优

基于表名的 Postgres 表分区

Postgres 窗口函数 - rank() 按 bigint 分区

Postgres 按值更改分区/分组