13

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

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)

4

3 回答 3

7

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

约束排除是一种查询优化技术,可以提高以上述方式定义的分区表的性能。举个例子:

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

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

您可以使用 EXPLAIN 命令来显示启用了 constraint_exclusion 的计划和禁用了它的计划之间的区别。

于 2010-02-10T12:44:58.537 回答
6

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

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

另外,请确保表上的 CHECK 条件以相同的方式定义...例如:CHECK (time_stamp < '2010-02-10'::timestamptz)

于 2010-07-06T17:40:35.467 回答
3

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

  1. 我已经用 type 的这个列索引了类型timestamp WITH time zone和分区约束的列timestamp WITHOUT time zone

  2. 需要修复ANALYZE所有子表的约束后。

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

我有要求,CURRENT_DATE这是我的问题的一部分。

于 2013-04-01T15:55:13.290 回答