自动分区触发器无法按预期工作



我正在尝试实现表的自动分区

CREATE TABLE incoming_ais_messages (
id uuid NOT NULL,
"source" int4 NOT NULL,
ais_channel varchar(8) NOT NULL,
is_read bool NOT NULL,
"time_stamp" timestamptz NOT null,
address_type varchar(32) NOT NULL,
"text" varchar NOT NULL,
CONSTRAINT incoming_ais_messages_pkey PRIMARY KEY (id,time_stamp)
) partition by range ("time_stamp");

为此,我使用了一个函数:

create or replace function create_partition() returns trigger as $auto_partition$
begin
raise notice 'create_partion called';
execute 'create table if not exists incoming_ais_messages_partition_' || to_char(now()::date, 'yyyy_mm_dd') || ' partition of incoming_ais_messages 
for values from (''' || to_char(now()::date, 'yyyy-mm-dd') || ''') to (''' || to_char((now() + interval '1 day')::date, 'yyyy-mm-dd') || ''');';
return new;
end;
$auto_partition$  language plpgsql;

还有一个触发器,应该在任何插入之前调用它:

create trigger auto_partition
before insert on incoming_ais_messages
for each row
execute procedure create_partition();

然而,当我插入类似的内容时:

INSERT INTO incoming_ais_messages (id, "source", ais_channel, is_read, "time_stamp", address_type, "text")
VALUES('123e4567-e89b-12d3-a456-426614174000'::uuid, 0, 'A', false, now(), 'DIRECT', 'text');

我得到另一个错误:

SQL Error [23514]: ERROR: no partition of relation "incoming_ais_messages" found for row
Detail: Partition key of the failing row contains (time_stamp) = (2022-07-21 18:01:41.787604+03).

之后,我手动创建了分区:

create table if not exists incoming_ais_messages_partition_1970_01_01 partition of incoming_ais_messages 
for values from (now()::date) to ((now() + interval '1 day')::date);

执行相同的insert语句并得到错误:

SQL Error [55006]: ERROR: cannot CREATE TABLE .. PARTITION OF "incoming_ais_messages" because it is being used by active queries in this session
Where: SQL statement "create table if not exists incoming_ais_messages_partition_2022_07_21 partition of incoming_ais_messages 
for values from ('2022-07-21') to ('2022-07-22');"
PL/pgSQL function create_partition() line 4 at EXECUTE

很高兴知道这里出了什么问题。我的解决方案基于此处描述的方法https://evilmartians.com/chronicles/a-slice-of-life-table-partitioning-in-postgresql-databases(章节:奖励:如何创建分区(

PostgreSQL希望在调用before ROW触发器之前知道新行将进入哪个分区,因此在CREATE有机会运行之前就会抛出错误。(请注意,博客示例是在一个表上使用触发器为不同的表创建分区(。

做你想做的事情是可能的(timescaledb扩展可以做到这一点,如果你想的话,你可以研究如何做(,但帮自己一个忙,只需预先创建很多分区,并在日历中添加一个注释,以便在未来添加更多分区(以及删除旧分区(。或者写一个cron作业来完成它。

最新更新