postgreSQL数据自动分区分表

postgreSQL数据自动分区分表

今天客户反馈说,系统有个模块访问有点慢。于是乎点进去瞅一瞅;发现有一个表是存储同步过来的实时数据;数据量已经到了千万的级别了。因此想说给这个表做个分区。这个项目用的数据库是PG;但由于我之前基本都是在用mysql的数据库;所以度年了一下PG的分表。网络上还是有蛮多的。发帖只是为了做个笔记,便于自己以后查阅!!!

分表过程可以参考:

PostgreSQL分区表(Table Partitioning)应用

贴上代码

-- my_table为要分区的源表
-- create_time 为分表字段(此处,根据这个时间字段,按年分表)
CREATE TRIGGER insert_my_table_trigger
BEFORE INSERT
ON my_table
FOR EACH ROW
EXECUTE PROCEDURE auto_insert_into_my_table('create_time');


-- 触发器函数
CREATE OR REPLACE FUNCTION auto_insert_into_my_table()
  RETURNS trigger AS 								-- 触发器函数必须是无参的,并且返回值为trigger
$$
DECLARE
    colunmName		text;			-- 父表中用于分区的时间字段的名称[必须首先初始化!!!],此处是create_time
    yearStr 		varchar(6);		-- 'YYYY'字串,用做分区子表的后缀
    tbExist 		boolean;		-- 分区子表 是否存在标志位
    stm 			text;			-- 分区开始时间(一年的01月01日)
    etm 			text;			-- 分区截止时间(一年的12月31日)
    sqlStr 			text;			-- sql语句字符串变量
    
BEGIN
	-- 当一个PL/pgSQL 函数作为一个触发器被调用时,系统自动在最外层的块创建一些[特殊的变量]。
    -- 调用前,必须首先初始化(时间字段名):colunmName [直接从调用参数中获取!!!];
	-- TG_ARGV:为[特殊的变量]之一,数据类型是text类型的数组。
	-- 表示CREATE TRIGGER命令传给触发器过程的所有参数。
	-- 下标从0开始。TG_ARGV[0]表示第一个参数,TG_ARGV[1]表示第二个参数,以此类推。 
	-- 如果下标小于0或大于等于CREATE TRIGGER命令传给触发器过程的参数的个数,将会返回一个空值。
	-- 此处取第一个参数,既create_time
    colunmName := TG_ARGV[0];
   
    -- 判断对应分区表 是否已经存在?
	-- NEW:为[特殊的变量]之一;数据类型是RECORD。
	-- 对于行级触发器,它存有INSERT或UPDATE操作产生的新的数据行。
    EXECUTE 'SELECT NEW.'||colunmName INTO sqlStr;
    yearStr := to_char(sqlStr::timestamp , 'YYYY');
	-- pg_class:postgreSQL内部表;记录表和几乎所有具有列或者像表的东西
	-- TG_TABLE_NAME:数据类型是name,表示触发器作用的表的名字。它与变量TG_RELNAME的作用是一样的。
    select count(*) INTO tbExist from pg_class where relname = (TG_TABLE_NAME||'_'||yearStr);
 
    -- 若不存在, 则插入前需 先创建子分区
    IF ( tbExist = false ) THEN  
        -- 创建子分区表
        stm := yearStr||'-01-01 00:00:00.000';
        etm := to_char(stm::timestamp + interval '1 year', 'yyyy-MM-dd HH24:mi:ss.ms');
        sqlStr := 'CREATE TABLE IF NOT EXISTS '||TG_TABLE_NAME||'_'||yearStr||
                  ' ( 
											CHECK('||colunmName||'>='''|| stm ||''' AND '||colunmName||'< '''|| etm |''' )
                     ) INHERITS ('||TG_TABLE_NAME||') ;'  ;  
        EXECUTE sqlStr;
 
        -- 创建索引
        sqlStr := 'CREATE INDEX IDX_'||TG_TABLE_NAME||'_'||yearStr||'_'||colunmName||' ON '
                  ||TG_TABLE_NAME||'_'||yearStr||' ('||colunmName||');' ;
        EXECUTE sqlStr;
       
    END IF;
 
    -- 插入数据到对应的分表中
    sqlStr := 'INSERT INTO '||TG_TABLE_NAME||'_'||yearStr||' SELECT NEW.*' ;
    EXECUTE sqlStr;
    RETURN NULL; 
END
$$ LANGUAGE plpgsql;
### PostgreSQL 中分库分表的实现方法与最佳实践 #### 1. 分库分表的核心概念 在大规模数据处理场景中,当单个数据库实例无法承载海量数据时,分库分表成为一种常见的解决方案。对于 PostgreSQL 而言,其支持多种分库分表的方式,主要包括垂直分表、垂直分库、水平分表以及水平分库[^3]。 - **垂直分表**:将一张宽表按照字段拆分成多张窄表,每张表只保留部分字段。这种方式适用于某些列访问频率较低的情况。 - **垂直分库**:将不同业务模块的数据存放到不同的数据库中,从而减少单一数据库的压力。 - **水平分表**:基于某种规则(如时间范围或哈希值),将同一张表的数据分布到多个子表中。例如 `product_order_0` 和 `product_order_1` 是典型的水平分表结果[^2]。 - **水平分库**:进一步扩展水平分表的概念,将数据分布在多个独立的数据库实例上。 #### 2. PostgreSQL 的分库分表工具与技术选型 PostgreSQL 提供了一些内置功能和第三方工具来简化分库分表的过程: - **分区表 (Partitioned Tables)** PostgreSQL 自版本 10 开始原生支持声明式分区表功能。可以通过 RANGE 或 LIST 方式定义分区逻辑。例如,按日期范围创建分区表: ```sql CREATE TABLE orders ( order_id bigint, order_date date, amount numeric ) PARTITION BY RANGE (order_date); CREATE TABLE orders_2023 QPARTITION OF orders FOR VALUES FROM ('2023-01-01') TO ('2024-01-01'); ``` - **逻辑复制 (Logical Replication)** 对于冷热数据分离的需求,可以利用逻辑复制机制,在主节点保存热数据的同时,将历史数据同步至其他节点存储[^4]。 - **中间件方案** 如果需要跨多个 PostgreSQL 实例进行分库分表操作,则可引入中间件完成路由和服务治理工作。常用的工具有: - **pg_shard**:由 Citus Data 推出的一款开源插件,允许开发者轻松构建分布式 PostgreSQL 数据库集群。 - **Citus**:作为 pg_shard 的升级版,提供了更加完善的分布式事务支持及性能调优选项。 #### 3. 设计注意事项 尽管分库分表能够有效缓解高并发读写压力,但也带来了额外复杂度。因此,在实际应用过程中需要注意以下几个方面的问题[^1]: - 数据一致性保障; - SQL 查询效率优化; - 主键冲突规避策略; - 备份恢复流程调整等。 #### 4. 性能优化建议 为了充分发挥 PostgreSQL 在分库分表环境下的潜力,可以从硬件资源配置、索引设计等方面入手实施全面优化措施。具体包括但不限于以下几点: - 合理规划磁盘 I/O 布局,确保各分片间负载均衡; - 针对频繁使用的查询条件建立覆盖索引(Covering Index),减少回表次数; - 定期执行 VACUUM ANALYZE 维护命令保持统计信息最新状态; ```python import psycopg2 def connect_to_partitioned_db(): conn = psycopg2.connect( dbname="orders", user="postgres", password="password", host="localhost" ) cursor = conn.cursor() query = """ SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31'; """ cursor.execute(query) results = cursor.fetchall() return results ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值