nic*_*314 4 postgresql index partitioning
我有一个范围分区表,我希望能够快速交换同一范围内的分区(即重新创建表并为其交换现有分区表)。但是,即使分区具有所有必需的索引,附加分区也需要很长时间。
-- create a partitioned table
create table "partitioned" (
"k1" INTEGER NOT NULL,
"k2" INTEGER NOT NULL,
PRIMARY KEY("k1", "k2")
) PARTITION BY RANGE "k1";
-- create the table to be added as a partition
create table "segment_1_000_000_to_2_000_000" (
"k1" INTEGER NOT NULL,
"k2" INTEGER NOT NULL,
PRIMARY KEY("k1", "k2")
);
-- insert 300,000,000 rows into table "segment_1_000_000_to_2_000_000" with "k1" values between values 1,000,000 and 2,000,000
-- ...
-- takes 5 minutes:
alter table "partitioned" attach partition "segment_1_000_000_to_2_000_000 for values from (1000000) to (2000000);
-- takes 38 milliseconds:
alter table "partitioned" detach partition "segment_1_000_000_to_2_000_000 for values from (1000000) to (2000000);
-- takes 5 minutes:
alter table "partitioned" attach partition "segment_1_000_000_to_2_000_000 for values from (1000000) to (2000000);
Run Code Online (Sandbox Code Playgroud)
作为参考,当我执行此操作时,表上没有运行其他查询。
此外,查询和min("k1")
运行max("k1")
速度非常快(约 51 毫秒),因此我认为由于范围边界检查,它不会附加缓慢,尽管边界检查似乎是缓慢的最可能的罪魁祸首。
那么为什么添加分区这么慢以及如何加快速度呢?
PostgreSQL 必须扫描要作为分区附加的表,以验证所有行是否都落入分区边界内。对于一张大桌子来说,这可能需要一段时间。如果新分区上已经存在拟合检查约束,则 PostgreSQL 可以跳过该检查:
ALTER TABLE segment_1_000_000_to_2_000_000
ADD CHECK (k1 IS NOT NULL AND number >= 1000000 AND number < 2000000);
Run Code Online (Sandbox Code Playgroud)
如果number
定义为NOT NULL
,则第一个检查可以省略。
client_min_messages
您可以通过设置为来验证您的约束是否良好debug1
,然后ALTER TABLE ... ATTACH
将发出类似的消息
ALTER TABLE segment_1_000_000_to_2_000_000
ADD CHECK (k1 IS NOT NULL AND number >= 1000000 AND number < 2000000);
Run Code Online (Sandbox Code Playgroud)