postgresql 按日期动态创建分区表

PostgreSQL中的动态分区表创建与触发器应用
该文描述了在PostgreSQL数据库中如何创建一个主表`tbl_vehicle_statistics`,并建立一个存储过程`auto_insert_tbl_vehicle_statistics`用于自动插入数据到按时间分区的子表。当在主表上执行INSERT操作时,触发器会检查并创建必要的分区表,同时为每个分区创建索引,确保数据正确分发。测试数据写入后,还提供了删除触发器和存储过程的命令。

1、创建主表

CREATE TABLE "public"."tbl_vehicle_statistics" (
  "id" serial PRIMARY KEY,
  "plate_code"  varchar(64),
  "plate_color" int4,
  "pass_time" timestamp
 );

2、创建存储过程

create or replace function auto_insert_tbl_vehicle_statistics()
returns trigger as 
$BODY$
declare 
    -- 分区后缀 
    column_name text := TG_ARGV[0];
    yyyymmddHHmmss text := to_char(NEW.pass_time,'yyyy-mm-dd hh24:mi:ss');  
    yyyymmdd text := to_char(NEW.pass_time,'yyyymmdd');  
    yyyymm text := to_char(NEW.pass_time,'yyyymm');  
    isExist boolean; 
    strSQL  text;
    startTime text;
    endTime text;
begin

	--判断对应分区表是否存在
	 select count(*) INTO isExist from pg_class where relname = (TG_RELNAME||'_'||yyyymmdd);
	--若不存在分区表:
	if (isExist = false) then
	   --创建子分区表
	    startTime := yyyymm||'01 00:00:00';
	    endTime := date_trunc('month',NEW.pass_time)  + interval '1 month';
	    strSQL := 'create table if not exists '|| TG_RELNAME ||'_'||yyyymmdd||
	              ' ( CHECK('|| column_name ||'>='''|| startTime ||''' 
                    AND '|| column_name ||'< '''|| endTime ||''' )
                    ) INHERITS ('||TG_RELNAME||') ;'  ;  
        EXECUTE strSQL;
       -- 创建索引
        strSQL := 'CREATE INDEX '||TG_RELNAME||'_'||yyyymmdd||'_INDEX_'||column_name|| ' ON '
                 ||TG_RELNAME||'_'||yyyymmdd||' ('||column_name||');' ;
        EXECUTE strSQL;

	end if;
    -- 插入数据到子分区
       strSQL := 'INSERT INTO '||TG_RELNAME||'_'||yyyymmdd||' SELECT $1.* ;' ;
       EXECUTE strSQL USING NEW;
    RETURN NULL; 
END
  
$BODY$
  language plpgsql; 

关于postgreSQL触发器内置的一些变量及其说明:

内置变量名说明
NEW数据类型是RECORD。对于行级触发器,它存有INSERT或UPDATE操作产生的新的数据行。对于语句级触发器,它的值是NULL。
OLD数据类型是RECORD。对于行级触发器,它存有被UPDATE或DELETE操作修改或删除的旧的数据行。对于语句级触发器,它的值是NULL。
TG_NAME数据类型是name,它保存实际被调用的触发器的名字。
TG_RELNAME数据类型是name,表示触发器作用的表的名字。它与变量TG_TABLE_NAME的作用是一样的。
TG_NARGS数据类型是integer,表示CREATE TRIGGER命令传给触发器过程的参数的个数。
TG_ARGV[]数据类型是text类型的数组。表示CREATE TRIGGER命令传给触发器过程的所有参数。下标从0开始。TG_ARGV[0]表示第一个参数,TG_ARGV[1]表示第二个参数,以此类推。 如果下标小于0或大于等于tg_nargs,将会返回一个空值。

3、为主表创建触发器

 CREATE TRIGGER tbl_vehicle_statistics_trigger
  BEFORE INSERT
  ON tbl_vehicle_statistics
  FOR EACH ROW
  EXECUTE PROCEDURE auto_insert_tbl_vehicle_statistics('pass_time');

4、测试数据写入

insert into tbl_vehicle_statistics(id,plate_code,plate_color,pass_time) 
VALUES(1,'京A0001',1,to_timestamp('2023-08-07 09:54:00','yyyy-mm-dd hh24:mi:ss'));

5、其他

(1)删除触发器

drop trigger tbl_vehicle_statistics_trigger on tbl_vehicle_statistics;

(2)删除存储过程

DROP function auto_insert_tbl_vehicle_statistics();

<think>嗯,用户想了解如何在PostgreSQL创建和管理分区表。我之前已经处理过类似的问题,所以需要回忆一下相关的知识。首先,PostgreSQL支持的分区类型有范围分区、列分区和哈希分区。我记得每个分区策略有不同的适用场景,比如范围分区适合按时间或数值范围划分数据,列分区适合按特定值,而哈希分区则用于均匀分布数据。 用户可能需要具体的步骤和示例,所以我得详细说明创建分区表的步骤。例如,创建的时候需要指定分区策略,然后创建并定义各自的边界条件。不过要注意,不同版本的PostgreSQL可能语法有所不同,尤其是原生分区表功能是在10版本引入的,之后每个版本可能有改进。所以需要提到版本差异,并建议使用较新的版本以获得更好的支持。 然后,管理部分包括添加新分区、删除旧分区、分区维护和查询优化。添加分区可能需要使用ALTER TABLE ... ATTACH PARTITION,或者直接创建。删除分区则需要注意数据的处理,比如使用DROP TABLE或者DETACH PARTITION。 示例部分很重要,用户可能需要实际的SQL代码来参考。比如,创建一个按时间范围分区的,然后插入数据并查看执行计划,验证分区是否生效。此外,还需要提到系统如pg_class和pg_partitioned_table,用于查询分区信息。 用户可能还关心性能优化,比如分区剪枝,这时候需要解释执行计划中的信息,确保查询能正确利用分区。另外,维护操作如索引创建,应该在父上自动应用到子,或者需要手动处理,这取决于版本。 还要考虑用户可能遇到的问题,比如分区键的选择,或者如何管理大量分区。比如,使用哈希分区时如何确定分区的数量,或者在范围分区中处理边界值的问题。可能需要提醒用户注意分区数量的管理,避免过多分区影响性能。 另外,引用中的信息提到PostgreSQL源码中的相关文件,虽然用户可能不需要深入代码,但可以提到这些资源供进一步学习。同时,引用[3]中的查询分区条件的方法,应该在管理部分给出示例,如使用pg_get_expr函数查看分区边界。 最后,确保回答结构清晰,分步骤说明创建和管理的方法,提供示例代码,并补充注意事项和最佳实践。可能还需要生成相关问题,比如性能优化、分区策略选择等,帮助用户进一步学习。</think>PostgreSQL创建和管理分区表的完整方法及示例说明如下: ### 一、分区表创建步骤 1. **确定分区策略** - **范围分区**:适用时间序列数据(如日期范围) - **列分区**:适用离散值分类(如地区代码) - **哈希分区**:适用均匀分布数据(如随机ID) 2. **创建**(PostgreSQL 10+原生分区语法) ```sql -- 范围分区示例 CREATE TABLE sales ( id SERIAL, sale_date DATE NOT NULL, amount NUMERIC ) PARTITION BY RANGE (sale_date); -- 列分区示例 CREATE TABLE region_data ( city_id INT, region_code VARCHAR(5) ) PARTITION BY LIST (region_code); -- 哈希分区示例(PostgreSQL 11+) CREATE TABLE user_logs ( log_id BIGSERIAL, user_id INT ) PARTITION BY HASH (user_id); ``` 3. **创建分区表** ```sql -- 范围子分区 CREATE TABLE sales_2023 PARTITION OF sales FOR VALUES FROM ('2023-01-01') TO ('2024-01-01'); -- 列子分区 CREATE TABLE region_east PARTITION OF region_data FOR VALUES IN ('BJ', 'SH', 'TJ'); -- 哈希子分区(创建4个哈希分区) CREATE TABLE user_logs_1 PARTITION OF user_logs FOR VALUES WITH (MODULUS 4, REMAINDER 0); ``` ### 二、分区表管理操作 1. **动态添加分区** ```sql -- 添加新年度分区 CREATE TABLE sales_2024 PARTITION OF sales FOR VALUES FROM ('2024-01-01') TO ('2025-01-01'); -- 使用ATTACH附加现有 CREATE TABLE sales_archive (LIKE sales INCLUDING INDEXES); ALTER TABLE sales ATTACH PARTITION sales_archive FOR VALUES FROM ('2000-01-01') TO ('2023-01-01'); ``` 2. **删除分区** ```sql -- 直接删除分区表 DROP TABLE sales_2023; -- 安全移除分区(保留数据) ALTER TABLE sales DETACH PARTITION sales_2023; ``` 3. **分区维护** ```sql -- 创建索引(自动传播到所有分区) CREATE INDEX ON sales (sale_date); -- 手动维护特定分区 VACUUM (ANALYZE) sales_2023; -- 查询分区元数据 SELECT relname, pg_get_expr(relpartbound, oid) FROM pg_class WHERE relpartbound IS NOT NULL; -- [^3] ``` ### 三、使用示例验证 ```sql -- 插入测试数据 INSERT INTO sales (sale_date, amount) VALUES ('2023-06-15', 100.00), ('2024-02-20', 200.00); -- 查看数据分布 EXPLAIN ANALYZE SELECT * FROM sales WHERE sale_date BETWEEN '2023-01-01' AND '2023-12-31'; -- 应显示只扫描sales_2023分区[^2] ``` ### 四、注意事项 1. **版本差异**:原生分区功能需PostgreSQL 10+,建议使用12+版本获得完整功能 2. **性能优化**: - 使用`CHECK`约束加速查询 - 通过`pg_partition_tree`视图查看分区层次 - 定期执行`ANALYZE`更新统计信息 3. **限制**: - 主键必须包含分区键 - 外键不能引用分区表 - 最大分区数默认32GB(可通过配置调整) ### 五、进阶管理技巧 1. **子分区(嵌套分区)** ```sql CREATE TABLE sales_2023_q1 PARTITION OF sales_2023 FOR VALUES FROM ('2023-01-01') TO ('2023-04-01'); ``` 2. **默认分区**(PostgreSQL 11+) ```sql CREATE TABLE sales_default PARTITION OF sales DEFAULT; ``` 3. **分区剪枝验证** ```sql SET enable_partition_pruning = on; EXPLAIN ANALYZE SELECT * FROM sales WHERE sale_date = '2023-07-01'; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值