问题:
pgsql数据库报错:
ERROR: cannot delete from table "xxxxx" because it does not have a replica identity and publishes update
解决方法:
ALTER TABLE xxxxx REPLICA IDENTITY FULL;
原因分析:
当前度娘搜到的最多的是“PostgreSQL不喜欢缺少复制主键的表,即使是临时表
”,也是来自于一个网友的帖子
由于对postgresql数据的原理不太理解,所有对这个回复还是比较懵逼的,所有就查询整理了一下postgresql数据库复制的相关内容;
===postgresql逻辑复制-复制标识逻辑复制
(Logical Replication),是一种根据数据对象的 复制标识
(Replica Identity)(通常是主键)复制数据对象及其变化的方法。逻辑复制
这个术语与 物理复制
相对应,物理复制使用精确的块地址与逐字节复制,而逻辑复制则允许对复制过程进行精细的控制。
逻辑复制
基于 发布(Publication)
与 订阅(Subscription)模
型:
1)一个 发布者(Publisher)上可以有多个发布,一个 订阅者(Subscriber)上可以有多个 订阅 。
2)一个发布可被多个订阅者订阅,一个订阅只能订阅一个发布者,但可订阅同发布者上的多个不同发布。
针对一张表的逻辑复制通常是这样的:订阅者获取发布者数据库上的一个快照,并拷贝表中的存量数据。一旦完成数据拷贝,发布者上的变更(增删改清)就会实时发送到订阅者上。订阅者会按照相同的顺序应用这些变更,因此可以保证逻辑复制的事务一致性。这种方式有时候又称为 事务性复制(transactional replication)
。
这个业务逻辑使用场景还是比较多得,平时在工作中也有同样的使用场景,需要实时监控数据库数据的变化,例如:数据库与缓存(redis)数据的一致性,数据库中的数据变更要同步到缓存中,可能很多通过采用的方式是通过主动查询的形式不断查询数据库进行判断数据是否存在变更,这样对性能消耗比较大,实时性有延迟,并且逻辑比较复杂,postgresql数据库复制逻辑就能在数据同步时实现被动通知的模式,实时性高、资源请求次数少;
类似于阿里开发的canal
工具,用于订阅通知mysql数据库的变更数据,阿里的PolarDB PostgreSQL
和腾讯的DIP
都支持postgresql数据库数据的订阅功能,有兴趣的可以了解一下,本人也会在后续的文章中整理postgresql发布订阅
的方式,因为我们也经常在工作中用到获取postgresql变更数据的场景;
复制标识:
1)为了能够复制UPDATE和DELETE操作,被发布的表必须配置有一个复制标识
,这样在订阅者那一端才能标识对于更新或删除合适的行。
2)默认情况下,复制标识就是主键(如果有主键)。也可以在复制标识上设置另一个唯一索引(有特定的额外要求)。如果表没有合适的键,那么可以设置成复制标识“full”,它表示整个行都成为那个键。不过,这样做效率很低,只有在没有其他方案的情况下才应该使用。
3)如果在发布者端设置了“full”之外的复制标识,在订阅者端也必须设置一个复制标识,它应该由相同的或者少一些的列组成。
4)如果在复制UPDATE或DELETE操作的发布中加入了没有复制标识的表,那么订阅者上后续的UPDATE或DELETE操作将导致错误。不管有没有复制标识,INSERT操作都能继续下去。
复制标识支持以下几种类型:主键、唯一索引、FULL(整行数据)
--主库删除'AAA'
hr=> delete from jobs where job_id='AAA';
ERROR: cannot delete from table "jobs" because it does not have a replica identity and publishes deletes
HINT: To enable deleting from the table, set REPLICA IDENTITY using ALTER TABLE.
REPLICA IDENTITY
建议设置成主键。PG这样做可以避免很多风险,在 MySQL进行主从复制时,有时会出现主从延迟,通常是由于没有主键或没有索引导致操作缓慢。而PG直接告诉你,如果没有REPLICA IDENTITY
,就不能进行delete和update同步。因此就不会发生更新或删除缓慢的情况。如未设定主键也可直接使用REPLICA IDENTITY FULL
。在FULL的情况下,所有列的值始终被写入WAL。这是最消耗资源的模式。我们这里只是演示,如果是大量更新删除的表,建议不要使用FULL。
INSERT
操作总是可以无视 复制标识 直接进行(因为插入一条新记录,在订阅者上并不需要定位任何现有记录;而删除和更新则需要通过复制标识 定位到需要操作的记录)。如果一个没有 复制标识 的表被加入到带有UPDATE和DELETE的发布中,后续的UPDATE和DELETE会导致发布者上报错。
复制身份与索引的正确配置:
表上的复制标识配置,与表上有没有索引是两件独立的事。尽管各种排列组合都是可能的,然而在实际使用中只有三种可行的情况,其他情况都无法正常完成逻辑复制的功能(如果不报错,通常也是侥幸)
1)表上有主键,使用默认的 default 复制标识,不需要额外配置。
2)表上没有主键,但是有非空唯一索引,显式配置 index 复制标识。
3)表上既没有主键也没有非空唯一索引,显式配置full复制标识(运行效率低,仅作为兜底方案)