分区表上的主键增加n(n> 1)而不是1。
试图以多种不同的方式重写plpgsql,但是没有运气。肯定有些东西我听不懂。
CREATE SCHEMA IF NOT EXISTS some_record_pool;
CREATE SEQUENCE some_record_pkey_seq;
create table some_record
(
id BIGINT not null DEFAULT nextval('some_record_pkey_seq'::regclass),
device_id bigint,
device_type bigint,
record_time timestamp,
module_serial_number bigint,
module_id bigint,
message_type bigint,
event_code bigint,
device_status bytea,
sequence_number bigint,
data_bytes bigint,
device_data bytea,
active boolean,
deleted boolean,
created_time timestamp default now() not null,
created_on timestamp with time zone default now() not null,
updated_on timestamp with time zone default now() not null
);
CREATE INDEX idx_device_id
ON public.some_record USING brin
(device_id)
TABLESPACE pg_default;
CREATE INDEX idx_module_id
ON public.some_record USING brin
(module_id)
TABLESPACE pg_default;
CREATE INDEX idx_er_created_time
ON public.some_record (cast(created_time as DATE));
----- CREATE TRIGGER ----------
CREATE OR REPLACE FUNCTION some_record_insert_function()
RETURNS TRIGGER AS
$$
DECLARE
partition_date TEXT;
partition_name TEXT;
start_of_month TEXT;
end_of_next_month TEXT;
BEGIN
partition_date := to_char(NEW.created_time, 'YYYY_MM');
partition_name := 'some_record_' || partition_date;
start_of_month := to_char((NEW.created_time), 'YYYY-MM') || '-01';
end_of_next_month := to_char((NEW.created_time + interval '1 month'), 'YYYY-MM') || '-01';
IF NOT EXISTS
(SELECT 1
FROM information_schema.tables
WHERE table_name = partition_name)
THEN
RAISE NOTICE 'A partition has been created %', partition_name;
EXECUTE format(
E'CREATE TABLE some_record_pool.%I ' ||
E'(CHECK ( date_trunc(\'day\', created_time) >= ''%s'' ' ||
E'AND date_trunc(\'day\', created_time) < ''%s'')) INHERITS (public.some_record)',
partition_name, start_of_month, end_of_next_month);
-- EXECUTE format('GRANT SELECT ON TABLE %I TO readonly',
-- partition_name); -- use this if you use role based permission
ELSE
RAISE NOTICE 'A partition DOES NOT EXIST %', partition_name;
END IF;
EXECUTE format(
'INSERT INTO some_record_pool.%I (device_id, device_type, ' ||
'record_time, module_serial_number, module_id, message_type, ' ||
'event_code, device_status, sequence_number, data_bytes, device_data,' ||
' active, deleted) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)',
partition_name) using NEW.device_id, NEW.device_type,
NEW.record_time, NEW.module_serial_number, NEW.module_id, NEW.message_type,
NEW.event_code, NEW.device_status, NEW.sequence_number, NEW.data_bytes,
NEW.device_data, NEW.active, NEW.deleted;
RETURN NEW;
END
$$
LANGUAGE plpgsql;
CREATE TRIGGER insert_some_record_trigger
BEFORE INSERT ON public.some_record
FOR EACH ROW EXECUTE PROCEDURE public.some_record_insert_function();
--- INSERTING DATA FOR TESTING
INSERT INTO some_record (
event_record_id, timestamp, event_description_id, event_source_label, event_source_track, event_source_direction,
measurement_description, measurement_value, hw_address_module_id, hw_address_rlc_address, sub_system_source,
event_type, device_id, active, deleted) VALUES(1, 2, to_timestamp('1953-10-21 14:30:46.555337', 'YYYY-MM-DD HH:MI:SS.US'), 1, 1, 1, 1, NULL, 1, 9, E'9 B
00000000 92 FF 3C 00 7F 00 00 03 E8 .ÿ<.....è
', TRUE, FALSE, to_timestamp('2019-10-21 14:30:46.555337', 'YYYY-MM-DD HH:MI:SS.US'), to_timestamp('2019-10-21 14:30:46.555337', 'YYYY-MM-DD HH:MI:SS.US'));
代码的重点是自动创建分区并在存在分区的情况下插入数据。
主键应增加一个,但不能这样操作仅一次运行的预期输出是id:1
在postgres 12上测试的有效解决方案如下:
/** TABLE PARTITIONING EVENT RECORD **/
-- CREATE PROPER SCHEMA
CREATE SCHEMA IF NOT EXISTS test_par_pool;
-- CREATE PROPER TABLE
CREATE TABLE test_part
(
id bigserial not null
constraint test_part_pkey
primary key,
device_id bigint,
device_type bigint,
record_time timestamp,
module_serial_number bigint,
module_id bigint,
message_type bigint,
event_code bigint,
device_status bytea,
sequence_number bigint,
data_bytes bigint,
device_data bytea,
active boolean,
deleted boolean,
created_time timestamp default now() not null,
created_on timestamp with time zone default now() not null,
updated_on timestamp with time zone default now() not null
);
-- CREATE MINIMAL INDEXES
CREATE INDEX idx_device_id
ON public.test_part USING brin
(device_id)
TABLESPACE pg_default;
CREATE INDEX idx_module_id
ON public.test_part USING brin
(module_id)
TABLESPACE pg_default;
CREATE INDEX idx_er_created_time
ON public.test_part (cast(created_time as DATE));
-- CREATE INSERT FUNCTIONS
CREATE OR REPLACE FUNCTION test_par_insert_function()
RETURNS TRIGGER AS
$$
DECLARE
partition_date TEXT;
partition TEXT;
start_of_month TEXT;
end_of_next_month TEXT;
stmt TEXT;
BEGIN
partition_date := to_char(NEW.created_time, 'YYYY_MM');
partition := TG_RELNAME || '_' || partition_date;
start_of_month := to_char((NEW.created_time), 'YYYY-MM') || '-01';
end_of_next_month := to_char((NEW.created_time + interval '1 month'), 'YYYY-MM') || '-01';
IF NOT EXISTS(SELECT relname FROM pg_class WHERE relname = partition) THEN
RAISE NOTICE 'A partition has been created %',partition;
stmt = 'CREATE TABLE test_par_pool.' || partition || ' (check (date_trunc(''day'', created_time) >= '
|| chr(39) || start_of_month || chr(39)
|| ' AND date_trunc(''day'', created_time) < '
|| chr(39) || end_of_next_month
|| chr(39) || ' )) INHERITS ( public.' || TG_RELNAME ||
');';
EXECUTE stmt;
END IF;
EXECUTE 'INSERT INTO test_par_pool.' || partition ||
' SELECT( public.' || TG_RELNAME || ' ' || quote_literal(NEW) || ').* RETURNING id;';
RETURN NULL;
END
$$
LANGUAGE plpgsql;
-- CREATE TRIGGER
CREATE TRIGGER insert_test_part_trigger
BEFORE INSERT ON public.test_part
FOR EACH ROW EXECUTE PROCEDURE public.test_par_insert_function();