我有一个基于timestamp(daily)
分区的表。该表也有一个默认分区。我们有一个cron作业,它创建新的空分区并删除旧分区。
由于一些错误,这个cron作业没有运行,我们最终在default
分区中有很多数据。现在新分区的创建需要很多时间。我找到了以下解释
每当你创建一个新的分区时,它必须扫描默认分区,以确保默认分区中没有一行属于新创建的分区。
我理解这一点,并认为在默认分区上的分区键(时间戳)上创建一个索引会加快新分区的添加。但这也不起作用,它仍然需要大量的时间来添加新分区。
为什么索引没有帮助?下面的查询是即时的
select count(*) from partitioned_table_default where timestamp > (now() + interval '1 days');
字符串
编辑:我检查了pg_stat_activity
来查看这个查询在做什么,它将等待事件显示为DataFileRead
。我还看到来自数据库的IO数量激增。这表明它仍然在从默认分区阅读数据。
任何帮助是高度赞赏!
1条答案
按热度按时间fae0ux8s1#
你可以在
src/backend/partitioning/partbounds.c
中看到check_default_partition_contents()
中的相关代码:字符串
因此,如果默认分区上有一个约束,意味着默认分区中没有任何行违反新的约束,则不需要扫描该分区。
型
否则,PostgreSQL会在默认分区上执行顺序扫描(
table_beginscan()
/table_scan_getnextslot()
/table_endscan()
)。PostgreSQL甚至没有尝试使用索引扫描。我不认为这背后有什么深层次的原因,它只是没有实现。
解决方法是在默认分区
NOT VALID
上创建一个检查约束,就像修改后的分区约束一样。然后您可以使用ALTER TABLE ... VALIDATE CONSTRAINT ...
来验证它,而无需锁定表。添加新分区后,再次删除约束。我的一般建议是,如果您计划稍后添加更多分区,请不要创建默认分区。