PostgreSQL+表分区:低效的 max() 和 min()

Posted

技术标签:

【中文标题】PostgreSQL+表分区:低效的 max() 和 min()【英文标题】:PostgreSQL+table partitioning: inefficient max() and min() 【发布时间】:2010-10-06 16:54:21 【问题描述】:

我有一个存储在 PostgreSQL 表中的巨大分区表。每个子表在其 id 上都有一个索引和一个检查约束,例如(为了清楚起见,删除了不相关的细节):

Master table: points
    Column     |            Type             |       Modifiers        
---------------+-----------------------------+------------------------
 id            | bigint                      |
 creation_time | timestamp without time zone | 
 the_geom      | geometry                    | 


Sub-table points_01
    Column     |            Type             |        Modifiers        
---------------+-----------------------------+-------------------------
     id            | bigint                      | 
 creation_time | timestamp without time zone | 
 the_geom      | geometry                    | 

Indexes:
    "points_01_pkey" PRIMARY KEY, btree (id)
    "points_01_creation_time_idx" btree (creation_time)
    "points_01_the_geom_idx" gist (the_geom) CLUSTER
Check constraints:
    "enforce_srid_the_geom" CHECK (srid(the_geom) = 4326)
    "id_gps_points_2010_08_22__14_47_04_check" 
               CHECK (id >= 1000000::bigint AND id <= 2000000::bigint)

现在,

SELECT max(id) FROM points_01

是即时的,但是:

SELECT max(id) FROM points

这是points_01 .. points_60 的主表,使用检查约束应该花费很少的时间,但需要一个多小时,因为查询计划程序不使用检查约束。

根据 PostgreSQL wiki(this page 的最后一部分),这是一个已知问题,将在下一个版本中修复。

是否有一个很好的技巧可以让查询规划器利用检查约束和子表的索引来进行max()min() 查询?

谢谢,

亚当

【问题讨论】:

你能展示你的执行计划吗? 【参考方案1】:

我不知道它是否会起作用,但你可以试试这个:

对于该会话,您可以禁用除索引的所有访问策略:

db=> set enable_seqscan = off;
db=> set enable_tidscan = off;
db=> -- your query goes here

这样,只会启用bitmapscanindexscan。 PostgreSQL 将别无选择,只能使用索引来访问表上的数据。

运行查询后,请记住通过执行以下操作重新启用 seqscantidscan

db=> set enable_seqscan = on;
db=> set enable_tidscan = on;

否则,从那时起,会话的这些访问策略将被禁用。

【讨论】:

这些设置是会话特定的还是全局的? 您可以通过更改“postgresql.conf”使它们全局化。但我强烈不鼓励你这样做。如果您使用 set,它们将是特定于会话的。正如我在答案中所说,禁用 seqscan 和 tidscan ONLY FOR THAT QUERY 并立即重新启用它们。【参考方案2】:

简短的回答:不。在这个时间点上,没有办法让 Postgres 规划器了解某些聚合函数可以首先检查子分区的约束。对于 min 和 max 的特定情况,它相当容易证明,但对于一般的聚合,它是一个困难的情况。

当你不得不做的时候,你总是可以把它写成几个分区的 UNION...

【讨论】:

【参考方案3】:

我对 postgres 了解不多,但你可以试试这个查询(由于缺乏 postgres 查询的经验,我的查询语法可能不正确):

SELECT id FROM points a WHERE id > ALL (SELECT id FROM x WHERE x.id != a.id)

我很好奇这是否可行。

【讨论】:

以上是关于PostgreSQL+表分区:低效的 max() 和 min()的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 AWS Glue Crawler 读取 PostgreSQL 表分区?

postgresql----表分区

PostgreSQL分区介绍

是否可以使用 JetBrains DataGrip 对表进行分区? (PostgreSQL)

PostgreSQL分区表

Postgresql查询当前表的分区