【问题标题】:Issues with postgresql-11 partitioning and primary key autoincrementpostgresql-11 分区和主键自动增量的问题
【发布时间】:2019-10-23 09:36:08
【问题描述】:

分区表上的主键递增 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

【问题讨论】:

    标签: database-partitioning postgresql-11


    【解决方案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();
    

    【讨论】:

      猜你喜欢
      • 2012-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-22
      • 2011-12-07
      • 1970-01-01
      • 2011-07-16
      • 2013-04-18
      相关资源
      最近更新 更多