Postgres数据库主动化分区

打印 上一主题 下一主题

主题 1005|帖子 1005|积分 3025

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
一.创建主动化分区配置表并插入数据

  1. -- Table: managerdb.par_info
  2. -- DROP TABLE IF EXISTS managerdb.par_info;
  3. CREATE TABLE IF NOT EXISTS managerdb.par_info
  4. (
  5.     table_schema character varying(255) COLLATE pg_catalog."default" NOT NULL,
  6.     table_name character varying(255) COLLATE pg_catalog."default" NOT NULL,
  7.     par_column character varying(255) COLLATE pg_catalog."default",
  8.     keep_data_days bigint,
  9.     step_length bigint,
  10.     create_next_intervals bigint,
  11.     update_time timestamp with time zone NOT NULL DEFAULT now(),
  12.     min_partition_name character varying(300) COLLATE pg_catalog."default",
  13.     max_partition_name character varying(300) COLLATE pg_catalog."default",
  14.     CONSTRAINT par_info_pkey PRIMARY KEY (table_schema, table_name)
  15. )
  16. TABLESPACE pg_default;
  17. ALTER TABLE IF EXISTS managerdb.par_info
  18.     OWNER to postgres;
  19. COMMENT ON COLUMN managerdb.par_info.table_schema
  20.     IS '模式名';
  21. COMMENT ON COLUMN managerdb.par_info.table_name
  22.     IS '表名';
  23. COMMENT ON COLUMN managerdb.par_info.par_column
  24.     IS '分区字段名';
  25. COMMENT ON COLUMN managerdb.par_info.keep_data_days
  26.     IS '分区保留时长';
  27. COMMENT ON COLUMN managerdb.par_info.step_length
  28.     IS '步长';
  29. COMMENT ON COLUMN managerdb.par_info.create_next_intervals
  30.     IS '预分区时间';
  31. COMMENT ON COLUMN managerdb.par_info.update_time
  32.     IS '更新时间';
  33. COMMENT ON COLUMN managerdb.par_info.min_partition_name
  34.     IS '最小分区';
  35. COMMENT ON COLUMN managerdb.par_info.max_partition_name
  36.     IS '最大分区';
  37. -- Index: par_info_table_name_idx
  38. -- DROP INDEX IF EXISTS managerdb.par_info_table_name_idx;
  39. CREATE INDEX IF NOT EXISTS par_info_table_name_idx
  40.     ON managerdb.par_info USING btree
  41.     (table_name COLLATE pg_catalog."default" ASC NULLS LAST)
  42.     TABLESPACE pg_default;
复制代码
插入四张测试表,根据范围分区

  1. INSERT INTO managerdb.par_info (table_schema,table_name,par_column,keep_data_days,
  2. step_length,create_next_intervals,update_time,min_partition_name,max_partition_name) VALUES
  3.          ('public','t_01','ctime',7,1,15,'2024-12-02 17:30:39+08',null,null),
  4.          ('public','t_02','ctime',7,1,15,'2024-12-02 17:30:39+08',null,null),
  5.          ('public','t_03','cint',7,1,15,'2024-12-02 17:30:39+08',null,null),
  6.          ('public','t_04','cint',7,1,15,'2024-12-02 17:30:39+08',null,null);
复制代码

二.创建需要分区的表

  1. CREATE TABLE IF NOT EXISTS public.t_01
  2. (
  3.     id integer NOT NULL,
  4.     name character varying(100) COLLATE pg_catalog."default",
  5.     ctime timestamp without time zone NOT NULL,
  6.     CONSTRAINT t_01_pkey PRIMARY KEY (ctime, id)
  7. );
  8. CREATE TABLE IF NOT EXISTS public.t_02
  9. (
  10.     id integer NOT NULL,
  11.     name character varying(100) COLLATE pg_catalog."default",
  12.     ctime timestamp without time zone NOT NULL,
  13.     CONSTRAINT t_02_pkey PRIMARY KEY (ctime, id)
  14. );
  15. CREATE TABLE IF NOT EXISTS public.t_03
  16. (
  17.     id integer NOT NULL,
  18.     name character varying(100) COLLATE pg_catalog."default",
  19.     cint bigint NOT NULL,
  20.     CONSTRAINT t_03_pkey PRIMARY KEY (ctime, id)
  21. );
  22. CREATE TABLE IF NOT EXISTS public.t_04
  23. (
  24.     id integer NOT NULL,
  25.     name character varying(100) COLLATE pg_catalog."default",
  26.     cint bigint NOT NULL,
  27.     CONSTRAINT t_04_pkey PRIMARY KEY (ctime, id)
  28. );
复制代码
三.创建数据库函数,查询表布局,用于普通表转分区表

查询表索引函数
  1. -- FUNCTION: managerdb.get_index_ddl(character varying, character varying, character varying)
  2. -- DROP FUNCTION IF EXISTS managerdb.get_index_ddl(character varying, character varying, character varying);
  3. CREATE OR REPLACE FUNCTION managerdb.get_index_ddl(
  4.         namespace character varying,
  5.         tablename character varying,
  6.         ctype character varying)
  7.     RETURNS character varying
  8.     LANGUAGE 'plpgsql'
  9.     COST 100
  10.     VOLATILE PARALLEL UNSAFE
  11. AS $BODY$
  12. declare
  13. tt oid ;
  14. aname character varying default '';
  15. begin
  16.        tt := oid from pg_class where relname= tablename and relnamespace =(select oid from pg_namespace  where nspname=namespace) ;
  17.        aname:=  array_to_string(
  18.                 array(
  19.                        select a.attname  from pg_attribute  a
  20.                                 where a.attrelid=tt and  a.attnum   in (               
  21.                                 select unnest(conkey) from pg_constraint c where contype=ctype
  22.                                 and conrelid=tt  and array_to_string(conkey,',') is not null  
  23.                         )
  24.                 ),',');
  25.        
  26.         return aname;
  27. end
  28. $BODY$;
  29. ALTER FUNCTION managerdb.get_index_ddl(character varying, character varying, character varying)
  30.     OWNER TO postgres;
复制代码
查询创建表索引
  1. -- FUNCTION: managerdb.get_table_ddl(character varying, character varying)
  2. -- DROP FUNCTION IF EXISTS managerdb.get_table_ddl(character varying, character varying);
  3. CREATE OR REPLACE FUNCTION managerdb.get_table_ddl(
  4.         namespace character varying,
  5.         tablename character varying)
  6.     RETURNS character varying
  7.     LANGUAGE 'plpgsql'
  8.     COST 100
  9.     VOLATILE PARALLEL UNSAFE
  10. AS $BODY$
  11. declare
  12. tableScript character varying default '';
  13. idx_text character varying default '';
  14. table_flag oid;
  15. begin
  16. -- columns
  17. tableScript:=tableScript || ' CREATE TABLE '|| namespace || '.' ||tablename|| ' ( '|| chr(13)||chr(10) || array_to_string(
  18.   array(
  19. select '   ' || concat_ws('  ',fieldName, fieldType, fieldLen, indexType, isNullStr,attdefault, fieldComment ) as column_line
  20. from (
  21. select fieldName,case when attdefault like 'default nextval%' then null else fieldType end fieldType,
  22. fieldLen,indexType,
  23. case when attdefault like 'default nextval%' then null else isNullStr end isNullStr,
  24. case when attdefault like 'default nextval%' then 'serial' else attdefault end attdefault,
  25. fieldComment
  26. from (
  27. select a.attname as fieldName,
  28. pg_catalog.format_type(a.atttypid, a.atttypmod) as fieldType,
  29. null as fieldLen,
  30. null as indexType,
  31. (case when a.attnotnull=true then 'not null' else 'null' end) as isNullStr,
  32. (SELECT 'default '||substring(pg_catalog.pg_get_expr(d.adbin, d.adrelid, true) for 128) FROM pg_catalog.pg_attrdef d
  33.             WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef
  34. ) as attdefault,
  35. null as fieldComment
  36. FROM pg_catalog.pg_attribute a
  37.     JOIN pg_catalog.pg_class c ON a.attrelid = c.oid
  38.     JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid
  39.     LEFT JOIN pg_catalog.pg_class tc ON (c.reltoastrelid = tc.oid)
  40.     WHERE a.attrelid = (select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname =namespace and relname =tablename)
  41.     AND a.attnum > 0 AND NOT a.attisdropped
  42.     ORDER BY a.attnum
  43. ) t
  44. ) as string_columns
  45. ),','||chr(13)||chr(10));
  46. -- 约束
  47. idx_text:=array_to_string(
  48. array(
  49.         select concat('   CONSTRAINT ',conname ,c ,u,p,f)   from (
  50.                 select conname,
  51.                 case when contype='c' then  ' CHECK('|| ( select managerdb.get_index_ddl(namespace,tablename,'c') ) ||')' end  as c  ,
  52.                 case when contype='u' then  ' UNIQUE('|| ( select managerdb.get_index_ddl(namespace,tablename,'u') ) ||')' end as u ,
  53.                 case when contype='p' then ' PRIMARY KEY ('|| ( select managerdb.get_index_ddl(namespace,tablename,'p') ) ||')' end  as p  ,
  54.                 case when contype='f' then ' FOREIGN KEY('|| ( select managerdb.get_index_ddl(namespace,tablename,'u') ) ||') REFERENCES '||
  55.                 (select p.relname from pg_class p where p.oid=c.confrelid )  || '('|| ( select managerdb.get_index_ddl(namespace,tablename,'u') ) ||')' end as  f
  56.                 from pg_constraint c
  57.                 where contype in('u','c','f','p') and conrelid=(
  58.                         select oid  from pg_class  where relname=tablename and relnamespace =(
  59.                         select oid from pg_namespace where nspname = namespace
  60.                         )
  61.                  )
  62.         ) as t  
  63. ),','||chr(13)||chr(10));
  64. if length(idx_text) > 0  then
  65. tableScript:= tableScript||','||chr(13)||chr(10)||idx_text||') --PARTITION' ||chr(13)||chr(10) ||';';
  66. else
  67. tableScript:= tableScript||' ) --PARTITION' ||chr(13)||chr(10) ||';';
  68. end if;
  69. --- 获取非约束索引 column
  70. -- CREATE UNIQUE INDEX pg_language_oid_index ON pg_language USING btree (oid); -- table pg_language
  71. tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(
  72.         array(
  73.                 select 'CREATE INDEX ' || indexrelname || ' ON ' ||namespace || '.' || tablename || ' USING btree '|| '(' || attname || ');' from (
  74.                  SELECT
  75.                     i.relname AS indexrelname ,  x.indkey,
  76.                     
  77.                     ( select array_to_string (
  78.                         array(
  79.                                 select a.attname from pg_attribute a where attrelid=c.oid and a.attnum in ( select unnest(x.indkey) )
  80.                              )
  81.                      ,',' ) )as attname
  82.                     
  83.                    FROM pg_class c
  84.                    JOIN pg_index x ON c.oid = x.indrelid
  85.                    JOIN pg_class i ON i.oid = x.indexrelid
  86.                    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
  87.                    WHERE  c.relname=tablename and i.relname not in
  88.                           ( select constraint_name from information_schema.key_column_usage  where  table_name=tablename  )
  89.                 )as t
  90. ) ,','|| chr(13)||chr(10));
  91.                        
  92. -- COMMENT COMMENT ON COLUMN sys_activity.id IS '主键';
  93. tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(
  94. array(
  95. SELECT 'COMMENT ON COLUMN ' || namespace || '.' || tablename || '.' || a.attname ||' IS  '|| ''''|| d.description ||''''||';'
  96. FROM pg_class c
  97. JOIN pg_description d ON c.oid=d.objoid
  98. JOIN pg_attribute a ON c.oid = a.attrelid
  99. WHERE c.relname=tablename
  100. AND a.attnum = d.objsubid), chr(13)||chr(10)) ;
  101. -- COMMENT COMMENT ON table sys_activity  IS '表名';
  102. tableScript:= tableScript || chr(13)||chr(10) || chr(13)||chr(10) || array_to_string(
  103. array(
  104. SELECT 'COMMENT ON table ' || namespace || '.' || tablename ||' IS  '|| ''''|| d.description ||''''||';'
  105. FROM pg_class c
  106. inner join pg_description d on c.oid=d.objoid
  107. where d.objsubid=0 and c.oid=(select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname =namespace and relname =tablename)
  108. ), chr(13)||chr(10)) ;
  109. return format(tableScript);
  110. end
  111. $BODY$;
  112. ALTER FUNCTION managerdb.get_table_ddl(character varying, character varying)
  113.     OWNER TO postgres;
  114.        
  115.        
复制代码

四.创建存储过程主动分区

创建普通表转分区表存储过程
  1. -- PROCEDURE: managerdb.partition_verify(character varying, character varying, character varying, bigint, bigint, bigint)
  2. -- DROP PROCEDURE IF EXISTS managerdb.partition_verify(character varying, character varying, character varying, bigint, bigint, bigint);
  3. CREATE OR REPLACE PROCEDURE managerdb.partition_verify(
  4.         IN p_schema_name character varying,
  5.         IN p_table_name character varying,
  6.         IN p_par_column character varying,
  7.         IN p_keep_data_days bigint,
  8.         IN p_step_length bigint,
  9.         IN p_create_next_intervals bigint)
  10. LANGUAGE 'plpgsql'
  11. AS $BODY$
  12. DECLARE
  13.    error_message text;
  14.    i int :=1;
  15.    is_par bigint;
  16.    l_itera bigint :=p_keep_data_days+p_create_next_intervals;
  17.    par_name varchar(100);
  18.    par_table_name varchar(100);
  19.    start_data varchar(100);
  20.    end_data  varchar(100);
  21.    sql_create varchar(4000);
  22.    sql_text varchar(4000);
  23.    sql_insert varchar(4000);
  24.    l_partition_type varchar(100);
  25.    max_par varchar(100);
  26.    min_par varchar(100);
  27. begin
  28. select count(1) into is_par
  29. from pg_partitioned_table a
  30. inner join pg_class c on a.partrelid =c.oid
  31. inner join pg_namespace n on c.relnamespace=n.oid
  32. where c.relname=p_table_name and n.nspname=p_schema_name;
  33.     -- 检查分区字段类型
  34.         SELECT data_type INTO l_partition_type
  35.         FROM information_schema.columns
  36.         WHERE table_schema = p_schema_name
  37.         AND table_name = p_table_name
  38.         AND column_name = p_par_column;
  39. raise notice '分区字段类型为:%',l_partition_type;
  40. if is_par=1 then
  41.   raise notice '该表是分区表';
  42. else
  43. par_table_name:=p_table_name||'_par';
  44. raise notice '%.%该表不是分区表!!!',p_schema_name,p_table_name;
  45. select replace(managerdb.get_table_ddl(p_schema_name,p_table_name),'--PARTITION','PARTITION BY RANGE ('||p_par_column||')') into sql_create;
  46. select replace(sql_create,p_table_name,par_table_name) into sql_create;
  47. raise notice '创建中间分区表%.%!!!',p_schema_name,par_table_name;
  48. raise notice 'table_create_sql: %', sql_create;
  49. execute sql_create;
  50. for i in 1..l_itera loop
  51. par_name = p_schema_name||'.'||p_table_name||'_'||to_char(current_date+(interval '1 day' *(p_create_next_intervals-i)*p_step_length),'yyyymmdd');
  52.   if l_partition_type = 'timestamp without time zone' then
  53.    start_data = ''''||to_char(current_date+(interval '1 day' *(p_create_next_intervals-i)*p_step_length),'yyyy-mm-dd'||' 00:00:00')||'''';
  54.    end_data = ''''||to_char(current_date+(interval '1 day' *(p_create_next_intervals+1-i)*p_step_length),'yyyy-mm-dd'||' 00:00:00')||'''';
  55.   else -- if l_partition_type='integer' or l_partition_type='bigint' then
  56.    start_data = (date_part('epoch',current_date+(interval '1 day' *(p_create_next_intervals-i)*p_step_length)))::int8;
  57.    end_data = (date_part('epoch',current_date+(interval '1 day' *(p_create_next_intervals+1-i)*p_step_length)))::int8;
  58.   end if;
  59.   sql_text='CREATE TABLE '||par_name||' PARTITION OF '||p_schema_name||'.'||par_table_name||' FOR VALUES FROM ('||start_data||') TO ('||end_data||');';
  60.   raise notice 'partition_create_sql: %', sql_text;
  61.   execute sql_text;
  62. end loop;
  63. end if;
  64. if l_partition_type = 'timestamp without time zone' then
  65.    max_par:=''''||to_char(current_date+(interval '1 day' *(p_create_next_intervals)*p_step_length),'yyyy-mm-dd'||' 00:00:00')||'''';
  66.    min_par:=''''||to_char(current_date-(interval '1 day' *(p_keep_data_days)*p_step_length),'yyyy-mm-dd'||' 00:00:00')||'''';
  67. else
  68.    max_par = (date_part('epoch',current_date+(interval '1 day' *(p_create_next_intervals)*p_step_length)))::int8;
  69.    min_par = (date_part('epoch',current_date-(interval '1 day' *(p_keep_data_days)*p_step_length)))::int8;
  70. end if;
  71. sql_insert:='insert into '||p_schema_name||'.'||par_table_name||chr(13)||chr(10)||'select * from '||p_schema_name||'.'||p_table_name
  72.            ||' where '||p_par_column||'>='||min_par||' and '||p_par_column||'<'||max_par||';';
  73. raise notice '将历史数据导入中间分区表sql:%',sql_insert;
  74. execute sql_insert;
  75. sql_insert:='alter table '||p_schema_name||'.'||p_table_name||' rename to '||p_table_name||'_bak;';
  76. raise notice '将原表重命名:%',sql_insert;
  77. execute sql_insert;
  78. sql_insert:='alter table '||p_schema_name||'.'||par_table_name||' rename to '||p_table_name||';';
  79. raise notice '将中间分区表重命名:%',sql_insert;
  80. execute sql_insert;
  81. EXCEPTION
  82.         WHEN OTHERS THEN
  83.                 GET STACKED DIAGNOSTICS error_message = MESSAGE_TEXT;
  84.                 RAISE NOTICE '捕获到异常信息*********************************ERROR************************************';
  85.                 RAISE NOTICE 'ERROR:%',error_message;
  86.                 RAISE NOTICE '捕获到异常信息*********************************ERROR************************************';
  87. end;
  88. $BODY$;
  89. ALTER PROCEDURE managerdb.partition_verify(character varying, character varying, character varying, bigint, bigint, bigint)
  90.     OWNER TO postgres;
复制代码
创建分区表定时增减分区存储过程
  1. -- PROCEDURE: managerdb.partition_maintenance(character varying, character varying, character varying, bigint, bigint, bigint)
  2. -- DROP PROCEDURE IF EXISTS managerdb.partition_maintenance(character varying, character varying, character varying, bigint, bigint, bigint);
  3. CREATE OR REPLACE PROCEDURE managerdb.partition_maintenance(
  4.         IN p_schema_name character varying,
  5.         IN p_table_name character varying,
  6.         IN p_par_column character varying,
  7.         IN p_keep_data_days bigint,
  8.         IN p_step_length bigint,
  9.         IN p_create_next_intervals bigint)
  10. LANGUAGE 'plpgsql'
  11. AS $BODY$
  12. DECLARE
  13.    error_message text;
  14.    i int :=1;
  15.    is_par bigint;
  16.    par_cn bigint;
  17.    l_itera bigint :=p_keep_data_days+p_create_next_intervals;
  18.    par_name varchar(100);
  19.    start_data varchar(100);
  20.    end_data  varchar(100);
  21.    sql_text varchar(4000);
  22.    sql_del varchar(4000);
  23.    sql_update varchar(4000);
  24.    l_partition_type varchar(100);
  25.    max_par varchar(100);
  26.    min_par varchar(100);
  27.    his_par varchar(100);
  28.    csr_par cursor for select p.relname
  29.     from pg_class c
  30.     inner join pg_inherits i on c.oid = i.inhparent
  31.     inner join pg_class p on p.oid=i.inhrelid
  32.     where c.oid =(select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname=p_schema_name and relname=p_table_name)
  33.     order by p.relname;
  34. begin
  35. select count(1) into is_par
  36. from pg_partitioned_table a
  37. inner join pg_class c on a.partrelid =c.oid
  38. inner join pg_namespace n on c.relnamespace=n.oid
  39. where c.relname=p_table_name and n.nspname=p_schema_name;
  40. if is_par=1 then
  41.   raise notice '该表是分区表。';
  42. else
  43. raise notice '该表为普通表,需要进行分区表重建。';
  44. call managerdb.partition_verify(p_schema_name,p_table_name,p_par_column,p_keep_data_days,p_step_length,p_create_next_intervals);
  45. end if;
  46. -- 检查分区字段类型
  47. SELECT data_type INTO l_partition_type
  48. FROM information_schema.columns
  49. WHERE table_schema = p_schema_name
  50. AND table_name = p_table_name
  51. AND column_name = p_par_column;
  52. raise notice '该表分区字段类型为:%',l_partition_type;
  53. /* 查看分区表的分区情况
  54. select pg_get_expr(p.relpartbound, p.oid),p.relname
  55.         from pg_class c
  56.         inner join pg_inherits i on c.oid = i.inhparent
  57.         inner join pg_class p on p.oid=i.inhrelid
  58.         where c.oid =(select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname ='public' and relname ='t_01')
  59.         order by pg_get_expr(p.relpartbound, p.oid)
  60. */
  61. select max(p.relname) INTO max_par
  62. from pg_class c
  63. inner join pg_inherits i on c.oid = i.inhparent
  64. inner join pg_class p on p.oid=i.inhrelid
  65. where c.oid =(select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname=p_schema_name and relname=p_table_name);
  66. select min(p.relname) INTO min_par
  67. from pg_class c
  68. inner join pg_inherits i on c.oid = i.inhparent
  69. inner join pg_class p on p.oid=i.inhrelid
  70. where c.oid =(select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname=p_schema_name and relname=p_table_name);
  71. select count(1) INTO par_cn
  72. from pg_class c
  73. inner join pg_inherits i on c.oid = i.inhparent
  74. inner join pg_class p on p.oid=i.inhrelid
  75. where c.oid =(select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname=p_schema_name and relname=p_table_name);
  76. raise notice '该表的最大分区:%,最小分区:%,分区总数:%。',max_par,min_par,par_cn;
  77. -- 增加分区
  78. for i in 1..l_itera loop
  79. par_name = p_table_name||'_'||to_char(current_date+(interval '1 day' *(p_create_next_intervals-i)*p_step_length),'yyyymmdd');
  80.   -- raise notice '分区%',par_name;
  81.   if par_name>max_par then
  82.     if l_partition_type = 'timestamp without time zone' then
  83.      start_data = ''''||to_char(current_date+(interval '1 day' *(p_create_next_intervals-i)*p_step_length),'yyyy-mm-dd'||' 00:00:00')||'''';
  84.      end_data = ''''||to_char(current_date+(interval '1 day' *(p_create_next_intervals+1-i)*p_step_length),'yyyy-mm-dd'||' 00:00:00')||'''';
  85.     else
  86.      start_data = (date_part('epoch',current_date+(interval '1 day' *(p_create_next_intervals-i)*p_step_length)))::int8;
  87.      end_data = (date_part('epoch',current_date+(interval '1 day' *(p_create_next_intervals+1-i)*p_step_length)))::int8;
  88.     end if;
  89.     sql_text='CREATE TABLE '||p_schema_name||'.'||par_name||' PARTITION OF '||p_schema_name||'.'||p_table_name||' FOR VALUES FROM ('||start_data||') TO ('||end_data||');';
  90.     raise notice 'partition_create_sql: %', sql_text;
  91.     execute sql_text;
  92. else
  93.    raise notice '该表分区增加完成。。。';
  94.    exit;
  95. end if;
  96. end loop;
  97. -- 删除分区
  98. --应该最小分区和最大分区
  99. if l_partition_type = 'timestamp without time zone' then
  100.    max_par:=''''||to_char(current_date+(interval '1 day' *(p_create_next_intervals)*p_step_length),'yyyy-mm-dd'||' 00:00:00')||'''';
  101.    min_par:=''''||to_char(current_date-(interval '1 day' *(p_keep_data_days)*p_step_length),'yyyy-mm-dd'||' 00:00:00')||'''';
  102. else
  103.    max_par = (date_part('epoch',current_date+(interval '1 day' *(p_create_next_intervals)*p_step_length)))::int8;
  104.    min_par = (date_part('epoch',current_date-(interval '1 day' *(p_keep_data_days)*p_step_length)))::int8;
  105. end if;
  106. raise notice '该表应该最大分区:%,最小分区:%。',max_par,min_par;
  107. --应该最小分区名称
  108. par_name = p_table_name||'_'||to_char(current_date-(interval '1 day' *(p_keep_data_days)*p_step_length),'yyyymmdd');
  109. raise notice '应该最小分区名称%',par_name;
  110. open csr_par;
  111.     loop
  112.        fetch csr_par into his_par;
  113.            exit when not found;
  114.        -- raise notice '历史分区。。。%',his_par;
  115.            if his_par<par_name then
  116.              sql_del='drop table '||p_schema_name||'.'||his_par||';';
  117.                  raise notice '删除分区: %', sql_del;
  118.                  execute sql_del;
  119.            else
  120.              raise notice '最小分区已删除到: %', p_schema_name||'.'||his_par;
  121.              exit;
  122.            end if;
  123.     end loop;
  124. close csr_par;
  125. -- 更新自动化分区配置文件
  126. select max(p.relname) INTO max_par
  127. from pg_class c
  128. inner join pg_inherits i on c.oid = i.inhparent
  129. inner join pg_class p on p.oid=i.inhrelid
  130. where c.oid =(select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname=p_schema_name and relname=p_table_name);
  131. select min(p.relname) INTO min_par
  132. from pg_class c
  133. inner join pg_inherits i on c.oid = i.inhparent
  134. inner join pg_class p on p.oid=i.inhrelid
  135. where c.oid =(select c.oid from pg_class c,pg_namespace n where c.relnamespace=n.oid and n.nspname=p_schema_name and relname=p_table_name);
  136. sql_update='update managerdb.par_info set update_time='''||to_char(now(),'yyyy-mm-dd hh24:mi:ss')||''',min_partition_name='''||
  137.            min_par||''',max_partition_name='''||max_par||''' where table_schema='''||p_schema_name||''' and table_name='''||p_table_name||''';';
  138. raise notice '更新自动化分区配置文件sql:%',sql_update;
  139. execute sql_update;
  140. raise notice '---------------------------------------------------------------------------------';
  141. raise notice '----------------------分区表:%.%,自动化分区完成!!!------------------------',p_schema_name,p_table_name;
  142. raise notice '---------------------------------------------------------------------------------';
  143. EXCEPTION
  144.         WHEN OTHERS THEN
  145.                 GET STACKED DIAGNOSTICS error_message = MESSAGE_TEXT;
  146.         RAISE NOTICE '捕获到异常信息*********************************ERROR************************************';
  147.                 RAISE NOTICE 'ERROR:%',error_message;
  148.                 RAISE NOTICE '捕获到异常信息*********************************ERROR************************************';
  149.                        
  150. end;
  151. $BODY$;
  152. ALTER PROCEDURE managerdb.partition_maintenance(character varying, character varying, character varying, bigint, bigint, bigint)
  153.     OWNER TO postgres;
复制代码
创建全局主动化分区存储过程
  1. -- PROCEDURE: managerdb.partition_maintenance_all()
  2. -- DROP PROCEDURE IF EXISTS managerdb.partition_maintenance_all();
  3. CREATE OR REPLACE PROCEDURE managerdb.partition_maintenance_all(
  4.         )
  5. LANGUAGE 'plpgsql'
  6. AS $BODY$
  7. DECLARE
  8.    error_message text;
  9.    p_schema_name VARCHAR(255);
  10.    p_table_name VARCHAR(255);
  11.    p_par_column VARCHAR(255);
  12.    p_keep_data_days INT8;
  13.    p_step_length INT8;
  14.    p_create_next_intervals INT8;
  15.    csr cursor for SELECT table_schema,table_name,par_column,keep_data_days,step_length,create_next_intervals from managerdb.par_info;
  16. begin
  17.    raise notice '自动化分区日志开始(%)。。。',to_char(now(),'yyyy-mm-dd hh24:mi:ss');
  18.         open csr;
  19.     loop
  20.        fetch csr into p_schema_name,p_table_name,p_par_column,p_keep_data_days,p_step_length,p_create_next_intervals;
  21.            exit when not found;
  22.            raise notice '---------------------------------------------------------------------------------';
  23.        raise notice '----------------------分区表:%.%,自动化分区开始!!!------------------------',p_schema_name,p_table_name;
  24.        raise notice '---------------------------------------------------------------------------------';
  25.        raise notice '分区表:%.%,保留时长%天,时间间隔%天,预分区时间%天。',p_schema_name,p_table_name,p_keep_data_days,p_step_length,p_create_next_intervals;
  26.            call managerdb.partition_maintenance(p_schema_name,p_table_name,p_par_column,p_keep_data_days,p_step_length,p_create_next_intervals);
  27.     end loop;
  28.         close csr;
  29.         raise notice '...自动化分区执行完成!!!';
  30.         EXCEPTION
  31.             WHEN OTHERS THEN
  32.                     GET STACKED DIAGNOSTICS error_message = MESSAGE_TEXT;
  33.                         RAISE NOTICE '捕获到异常信息*********************************ERROR************************************';
  34.                         RAISE NOTICE 'ERROR:%',error_message;
  35.                         RAISE NOTICE '捕获到异常信息*********************************ERROR************************************';
  36. end;
  37. $BODY$;
  38. ALTER PROCEDURE managerdb.partition_maintenance_all()
  39.     OWNER TO postgres;
  40. COMMENT ON PROCEDURE managerdb.partition_maintenance_all()
  41.     IS '自动化分区调度入口';
复制代码

五.创建定时作业,每天定时执行

  1. vim /home/postgres/script/crontab_job_auto_partition.sh
  2. /home/postgres/bin/psql -p 15432 -d postgres -c "call managerdb.partition_maintenance_all()" > /home/postgres/scripts/partition_his.log 2>&1
复制代码
  1. crontab -e
  2. 0 2 * * * sh /home/postgres//scripts/crontab_job_auto_partition.sh
复制代码


六.试运行效果查看

执行日志
  1. [postgres@db scripts]$ cat partition_his.log
  2. NOTICE:  自动化分区日志开始(2024-12-02 17:30:39)。。。
  3. NOTICE:  ---------------------------------------------------------------------------------
  4. NOTICE:  ----------------------分区表:public.t_01,自动化分区开始!!!------------------------
  5. NOTICE:  ---------------------------------------------------------------------------------
  6. NOTICE:  分区表:public.t_01,保留时长7天,时间间隔1天,预分区时间15天。
  7. NOTICE:  该表是分区表。
  8. NOTICE:  该表分区字段类型为:timestamp without time zone
  9. NOTICE:  该表的最大分区:t_01_20241221,最小分区:t_01_20241127,分区总数:25。
  10. NOTICE:  该表分区增加完成。。。
  11. NOTICE:  该表应该最大分区:'2024-12-17 00:00:00',最小分区:'2024-11-25 00:00:00'。
  12. NOTICE:  应该最小分区名称t_01_20241125
  13. NOTICE:  最小分区已删除到: public.t_01_20241127
  14. NOTICE:  更新自动化分区配置文件sql:update managerdb.par_info set update_time='2024-12-02 17:30:39',min_partition_name='t_01_20241127',max_partition_name='t_01_20241221' where table_schema='public' and table_name='t_01';
  15. NOTICE:  ---------------------------------------------------------------------------------
  16. NOTICE:  ----------------------分区表:public.t_01,自动化分区完成!!!------------------------
  17. NOTICE:  ---------------------------------------------------------------------------------
  18. NOTICE:  ---------------------------------------------------------------------------------
  19. NOTICE:  ----------------------分区表:public.t_02,自动化分区开始!!!------------------------
  20. NOTICE:  ---------------------------------------------------------------------------------
  21. NOTICE:  分区表:public.t_02,保留时长7天,时间间隔1天,预分区时间15天。
  22. NOTICE:  该表是分区表。
  23. NOTICE:  该表分区字段类型为:timestamp without time zone
  24. NOTICE:  该表的最大分区:t_02_20241216,最小分区:t_02_20241125,分区总数:22。
  25. NOTICE:  该表分区增加完成。。。
  26. NOTICE:  该表应该最大分区:'2024-12-17 00:00:00',最小分区:'2024-11-25 00:00:00'。
  27. NOTICE:  应该最小分区名称t_02_20241125
  28. NOTICE:  最小分区已删除到: public.t_02_20241125
  29. NOTICE:  更新自动化分区配置文件sql:update managerdb.par_info set update_time='2024-12-02 17:30:39',min_partition_name='t_02_20241125',max_partition_name='t_02_20241216' where table_schema='public' and table_name='t_02';
  30. NOTICE:  ---------------------------------------------------------------------------------
  31. NOTICE:  ----------------------分区表:public.t_02,自动化分区完成!!!------------------------
  32. NOTICE:  ---------------------------------------------------------------------------------
  33. NOTICE:  ---------------------------------------------------------------------------------
  34. NOTICE:  ----------------------分区表:public.t_03,自动化分区开始!!!------------------------
  35. NOTICE:  ---------------------------------------------------------------------------------
  36. NOTICE:  分区表:public.t_03,保留时长7天,时间间隔1天,预分区时间15天。
  37. NOTICE:  该表是分区表。
  38. NOTICE:  该表分区字段类型为:bigint
  39. NOTICE:  该表的最大分区:t_03_20241216,最小分区:t_03_20241125,分区总数:22。
  40. NOTICE:  该表分区增加完成。。。
  41. NOTICE:  该表应该最大分区:1734393600,最小分区:1732492800。
  42. NOTICE:  应该最小分区名称t_03_20241125
  43. NOTICE:  最小分区已删除到: public.t_03_20241125
  44. NOTICE:  更新自动化分区配置文件sql:update managerdb.par_info set update_time='2024-12-02 17:30:39',min_partition_name='t_03_20241125',max_partition_name='t_03_20241216' where table_schema='public' and table_name='t_03';
  45. NOTICE:  ---------------------------------------------------------------------------------
  46. NOTICE:  ----------------------分区表:public.t_03,自动化分区完成!!!------------------------
  47. NOTICE:  ---------------------------------------------------------------------------------
  48. NOTICE:  ---------------------------------------------------------------------------------
  49. NOTICE:  ----------------------分区表:public.t_04,自动化分区开始!!!------------------------
  50. NOTICE:  ---------------------------------------------------------------------------------
  51. NOTICE:  分区表:public.t_04,保留时长7天,时间间隔1天,预分区时间15天。
  52. NOTICE:  该表是分区表。
  53. NOTICE:  该表分区字段类型为:bigint
  54. NOTICE:  该表的最大分区:t_04_20241216,最小分区:t_04_20241125,分区总数:22。
  55. NOTICE:  该表分区增加完成。。。
  56. NOTICE:  该表应该最大分区:1734393600,最小分区:1732492800。
  57. NOTICE:  应该最小分区名称t_04_20241125
  58. NOTICE:  最小分区已删除到: public.t_04_20241125
  59. NOTICE:  更新自动化分区配置文件sql:update managerdb.par_info set update_time='2024-12-02 17:30:39',min_partition_name='t_04_20241125',max_partition_name='t_04_20241216' where table_schema='public' and table_name='t_04';
  60. NOTICE:  ---------------------------------------------------------------------------------
  61. NOTICE:  ----------------------分区表:public.t_04,自动化分区完成!!!------------------------
  62. NOTICE:  ---------------------------------------------------------------------------------
  63. NOTICE:  ...自动化分区执行完成!!!
  64. CALL
复制代码
普通表主动化转换分区表乐成

定期增加删除分区乐成


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

泉缘泉

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表