Although the manual is extensive, during the production usage some problem have arose.
First, it was a problem with SELECT queries to partitioned tables that was fixed by a separate patch before Zabbix v.1.8.13. As of this version the patch is no more required. It brings a significant performance gain.
Secondly, it's about the fact that procedures in the manual above have an unpleasant effect. The data of first INSERT query that triggers a partition creation are always lost. I didn't have any desire to rewrite the proposed SQL, instead I implemented the obvious fix. To make INSERTs into history* tables beforehand. This also helps to solve the problem with table load. Partitioning procedures put a lock on tables and this can easily results in Zabbix malfunction. Planing will help you to avoid being awaken at 0.00 when Partitioning usually starts.
Example:
INSERT INTO history_uint (itemid, clock, value) VALUES ('1', extract( epoch FROM date_trunc('hour', now() + interval '12 hour')), '1')";The third fix is related to conditions that are wrongly used in the recipe above. I just put the corrected versions here. Corresponding lines are in the check_condition definition and I made them bold.
Hope, this notes will help someone.
CREATE OR REPLACE FUNCTION "public"."partition_every_day" (in parentoid oid, in scheme varchar, in clock int4) RETURNS text AS
$BODY$
declare
parent text := parentoid::regclass;
suffix text := to_char (to_timestamp(clock), '_YYYY_MM_DD');
child text := scheme || (select relname from pg_class where oid = parentoid) || suffix;
check_beg varchar;
check_end varchar;
check_condition varchar;
check_field varchar := null;
tmp record;
script text := '';
i int := 0;
j int := 0;
begin
perform child::regclass;
return child;
exception
when undefined_table then
check_beg = extract(epoch FROM date_trunc('day', to_timestamp(clock)));
check_end = extract(epoch FROM date_trunc('day', to_timestamp(clock) + interval '1 day'));
j = (select count(*) from pg_attribute where attrelid = parentoid and attnum >0);
for tmp in
select attname from pg_attribute where attrelid = parentoid and attnum >0 order by attnum loop
i = i + 1;
script = script || 'NEW.' || tmp.attname || case i when j then '' else ',' end;
if (col_description (parentoid, i) ~* 'partition') and (check_field is null)
then check_field = tmp.attname; end if;
end loop;
script = script || ')';
check_condition =
'(
' || check_field || ' >= ' || quote_literal (check_beg) || ' and
' || check_field || ' < ' || quote_literal (check_end) || '
)';
execute
'create table ' || child || '
(
constraint partition' || suffix || ' check '
|| check_condition || '
)
inherits (' || parent || ')';
execute
'create rule route' || suffix || ' as '
|| ' on insert to ' || parent || ' where '
|| check_condition
|| ' do instead insert into ' || child
|| ' values (' || script;
perform copy_constraints(parent, child);
perform copy_indexes(parent, child);
execute 'GRANT SELECT ON ' || child || ' TO some_other_user';
execute 'GRANT ALL ON ' || child || ' TO zabbix';
return child;
end;
$BODY$
LANGUAGE 'plpgsql'
-----
CREATE OR REPLACE FUNCTION "public"."partition_every_month" (in parentoid oid, in scheme varchar, in clock int4) RETURNS text AS
$BODY$
declare
parent text := parentoid::regclass;
suffix text := to_char (to_timestamp(clock), '_YYYY_MM');
child text := scheme || (select relname from pg_class where oid = parentoid) || suffix;
check_beg varchar;
check_end varchar;
check_condition varchar;
check_field varchar := null;
tmp record;
script text := '';
i int := 0;
j int := 0;
begin
perform child::regclass;
return child;
exception
when undefined_table then
check_beg = extract(epoch FROM date_trunc('month', to_timestamp(clock)));
check_end = extract(epoch FROM date_trunc('month', to_timestamp(clock) + interval '1 month'));
j = (select count(*) from pg_attribute where attrelid = parentoid and attnum >0);
for tmp in
select attname from pg_attribute where attrelid = parentoid and attnum >0 order by attnum loop
i = i + 1;
script = script || 'NEW.' || tmp.attname || case i when j then '' else ',' end;
if (col_description (parentoid, i) ~* 'partition') and (check_field is null)
then check_field = tmp.attname; end if;
end loop;
script = script || ')';
check_condition =
'(
' || check_field || ' >= ' || quote_literal (check_beg) || ' and
' || check_field || ' < ' || quote_literal (check_end) || '
)';
execute
'create table ' || child || '
(
constraint partition' || suffix || ' check '
|| check_condition || '
)
inherits (' || parent || ')';
execute
'create rule route' || suffix || ' as '
|| ' on insert to ' || parent || ' where '
|| check_condition
|| ' do instead insert into ' || child
|| ' values (' || script;
perform copy_constraints(parent, child);
perform copy_indexes(parent, child);
execute 'GRANT SELECT ON ' || child || ' TO xxx';
execute 'GRANT ALL ON ' || child || ' TO zabbix';
return child;
end;
$BODY$
LANGUAGE 'plpgsql'