PostgreSQL执行DROP TABLE分区CASCADE未级联删除关联分区问题
我有一个包含2个分区表的数据库,建表及数据插入语句如下:
create table ppp ( id serial not null, name varchar(255), primary key (id) ); insert into ppp (name) values ('ppp_first'); insert into ppp (name) values ('ppp_second'); create table rrr ( id serial not null, ppp_id integer not null, name varchar(255), primary key (id, ppp_id), foreign key (ppp_id) references ppp (id) on delete cascade ) partition by list(ppp_id); create table rrr1 partition of rrr for values in (1); create table rrr2 partition of rrr for values in (2); create table sss ( id bigserial not null, ppp_id integer not null, rrr_id integer not null, name varchar(255), primary key (id, ppp_id), foreign key (ppp_id, rrr_id) references rrr (ppp_id, id) on delete cascade ) partition by list(ppp_id); create table sss1 partition of sss for values in (1); create table sss2 partition of sss for values in (2); insert into rrr (ppp_id, name) values (1, 'rrr_first'); insert into rrr (ppp_id, name) values (2, 'rrr_second'); insert into sss (ppp_id, rrr_id, name) values (1, 1, 'sss_first'); insert into sss (ppp_id, rrr_id, name) values (2, 2, 'sss_second');
执行drop table rrr1 cascade;后,rrr1被成功删除,但关联的sss1分区并未被删除,查询结果如下:
=> select * from rrr; id | ppp_id | name ----+--------+------------ 2 | 2 | rrr_second (1 row) => select * from sss; id | ppp_id | rrr_id | name ----+--------+--------+------------ 1 | 1 | 1 | sss_first 2 | 2 | 2 | sss_second
为何sss1未被CASCADE级联删除?而不带CASCADE执行删除操作则会报错?
核心原因:两种CASCADE的作用对象完全不同
外键的
ON DELETE CASCADE只管数据,不管表对象
你定义的外键规则ON DELETE CASCADE,是当父表数据被删除时,自动删除子表中关联的数据。但你执行的DROP TABLE rrr1是删除表对象本身,不是删除表中的数据,这条规则根本不会触发,自然不会影响sss1的表对象或其中的数据。DROP TABLE ... CASCADE只删直接依赖被删表的对象
不带CASCADE执行DROP TABLE rrr1时报错,是因为sss父表的外键约束依赖于rrr父表的主键,而rrr1是rrr的分区,属于rrr表结构的一部分,直接删除会触发依赖检查报错。
加上CASCADE后,PostgreSQL只会级联删除那些直接引用rrr1这个表对象的数据库对象(比如直接基于rrr1创建的视图、触发器等),但sss1并不是直接依赖rrr1——它的依赖关系是关联到父表sss和rrr,和rrr1没有直接的对象级依赖,所以不会被级联删除。分区表的约束继承逻辑
外键约束是定义在sss父表上,指向的是rrr父表,而非某个具体分区rrr1。sss1作为sss的分区,继承的是父表的约束,它和rrr1之间只有数据层面的关联,没有对象层面的直接依赖,这也是DROP TABLE rrr1 CASCADE不会删除sss1的关键。
内容的提问来源于stack exchange,提问作者vvoodrovv

