pg_rewrite扩展是CyberTec公司开发的PostgreSQL扩展,可以很方便的在线将普通表转换成分区表。
一、安装配置
pg_rewrite只支持PostgreSQL 13及以上版本
git clone https://github.com/cybertec-postgresql/pg_rewrite.git cd pg_rewrite makemake install #修改配置文件wal_level = logical #因为是在线转换,所以如果在转换过程中源表的数据发生变化,pg_rewrite通过逻辑复制获取变化数据#因此需要复制槽max_replication_slots =1#需要预加载,但我在使用中发现不加入预加载项中也能正常使用shared_preload_libraries ='pg_rewrite'#安装配置完成后需要重启数据库。然后以超级用户身份创建扩展create extension pg_rewrite;
二、使用方法举例
假设普通表定义了如下:
CREATETABLE measurement ( id serial, city_id intnotnull, logdate datenotnull, peaktemp int, unitsales int, PRIMARY KEY(id, logdate)-- pg分区的要求,分区字段必须是主键或者唯一索引的一部分);
现在需要将上表转换成分区表,先创建分区表,pg_rewrite要求分区表跟普通表必须一模一样,包括字段、约束、索引......
CREATETABLE measurement_aux ( id serial, city_id intnotnull, logdate datenotnull, peaktemp int, unitsales int, PRIMARY KEY(id, logdate)) PARTITION BY RANGE (logdate);
接下来创建分区(本例创建range分区)
CREATETABLE measurement_y2006m02 PARTITION OF measurement_aux FOR VALUESFROM('2006-02-01') TO ('2006-03-01');CREATETABLE measurement_y2006m03 PARTITION OF measurement_aux FOR VALUESFROM('2006-03-01') TO ('2006-04-01');-- ...
使用pg_rewrite的partition_table函数转换分区,总共三个参数,参数一是源表、参数二是目的表,参数三指定转换完成后源表的新表名。
SELECT partition_table('measurement','measurement_aux','measurement_old');
执行些函数将数据从measurement(源表)复制到measurement_aux(目的表),然后它将以独占方式锁定measurement表,然后执行如下操作:
(1)将measurement重命名为measurement_old;
(2)将measurement_aux重命名为measurement。
转换完成后,measurement最终是分区表,而measurement_old是原来未分区的表。
三、过程监控
如果 partition_table()
需要很长时间才能完成,此间你可能想了解转换进度。pg_rewrite提供了pg_rewrite_progress视图。src_table、src_table和src_table_new
列包含partition_table()
函数的参数。ins_initial
是在“初始加载阶段”插入到新表中的元组的数量,即在处理开始之前存在于表中的元组的数量。另一方面, ins
, upd
和 del
是在表转换过程中插入、更新和删除的元组的数量。这些“转换中发生的数据变更”也必须合并到分区表中,否则它们会丢失。
四、限制
- 不支持外表;
- 被转换的表不能有外键;
五、参数
以下是对影响此扩展的函数行为的配置变量的说明。
rewrite.check_constraints
在开始复制数据之前,检查目标表是否与源表具有相同的约束,如果发现不同则抛出错误。通过将rewrite.check_constraints
设置为false,可以关闭约束检查。在这样做之前,请非常小心。
默认值为true。
rewrite.max_xlock_time
尽管其他事务在大多数情况下都可以对正在处理的表进行读写操作,但需要使用独占锁来完成处理(即处理剩余的并发更改并重命名这些表)。如果扩展阻止了太多对表的访问,可以考虑设置rewrite.max_xlock_time
参数。例如:
SET rewrite.max_xlock_time TO 100;
告知独占锁的持有时间不应超过0.1秒(100毫秒)。如果最后处理阶段需要更多时间,则释放排他锁,处理转换期间其他事务提交的更改,然后再次尝试最后阶段。如果超过锁定持续时间,则会报告错误。如果发生这种情况,应该增加该值,或者稍后在写入活动较少时尝试处理有问题的表。默认值为0,这意味着最终阶段可以根据需要花费任意长的时间。
六、并发
该扩展不会阻止其他事务在转换的某些阶段更改表。如果转换完成之前有其他进程执行了破坏性命令(比如ALTER TABLE...),则转换会中止,并且回滚所做的所有更改。
此扩展允许MVCC-Caveats第一段中描述的MVCC不安全行为。
七、锁
因为更改表名需要排他锁,所以更改表名时在很短的时间内将无法访问该表。
八、转换流程总结
1.用pg_dump -s -t 表名导出需要转换的表到指定sql文件中;
2.修改导出的sql文件,将原表名、主键、索引等内容修改为合适的值,一定不能与原表冲突,然后在create table语句里加上分区相关的内容;
3.在psql中执行修改后的sql文件;
4.根据分区表类型创建相应的分区,可以写成脚本,比如创建hash分区:
do language plpgsql $$ declare parts int:=32;--分区数量begin for i in0..parts-1 loop execute format('create table zmd_sell_product_par_p%s partition of zmd_sell_product_par for values with(MODULUS %s, REMAINDER %s)',i, parts, i); end loop;end;$$;
5.执行partition_table,如果出错,根据错误提示修改表结构。