数据库中何时可接受循环引用?
理论和实践,感谢任何帮助。
答案 0 :(得分:23)
考虑城市和州。每个城市都在一个州内。每个州都有一个首都。
CREATE TABLE city (
city VARCHAR(32),
state VARCHAR(32),
PRIMARY KEY (city),
FOREIGN KEY (state) REFERENCES state (state)
);
CREATE TABLE state (
state VARCHAR(32),
captial_city VARCHAR(32),
PRIMARY KEY (state),
FOREIGN KEY (captial_city) REFERENCES city (city)
);
第一个问题 - 您无法如图所示创建这些表。解决方案是在没有外键的情况下创建它们,然后再添加外键。
第二个问题 - 您无法在任何一个表中插入行,因为每个插入都需要另一个表中预先存在的行。解决方案是将其中一个外键列设置为NULL,并将该数据分两个阶段插入。 e.g。
INSERT INTO city (city, state) VALUES ('Miami', NULL);
INSERT INTO state (state, capital_city) VALUES ('Florida', 'Miami');
UPDATE city SET state='Florida' WHERE city='Miami';
答案 1 :(得分:13)
指向其他记录的记录在数据库中很有用。有时这些记录形成一个循环。这可能仍然有用。实践中唯一真正的烦恼就是避免违反约束条件。
例如,如果您有用户和事务表,则该用户可能具有指向其上一个事务的指针。您需要先插入事务,然后将last_transaction_id
更新为正确的值。虽然这两个记录都存在但您无法删除它们,因为user.last_transaction_id
指向transaction.id
和transaction.user_id
指向user.id
。这意味着没有事务的用户具有空last_transaction_id
。这也意味着您必须先删除该字段,然后才能删除该事务。
管理这些外键约束是一种痛苦,但肯定是可能的。如果稍后向数据库添加约束会引入新的循环依赖关系,则可能会出现问题。在这种情况下你必须要小心。但是,只要循环中的一个记录具有可空的外键字段,就可以中断循环并删除记录。只要您按正确的顺序插入记录,更新通常不会成为问题。
答案 2 :(得分:4)
Oracle层次查询语法的最新成员之一 - NOCYCLE
关键字 - 是出于明确的目的 - 处理数据中的循环引用。我没有看到它有任何问题,并且之前不得不处理这种模型。这并不困难,特别是在支持可延迟约束的Oracle中。
答案 3 :(得分:3)
技术上可行,但在删除记录时会产生各种问题,因为它会产生鸡蛋问题。这些问题通常会采取激烈的行动,例如手动删除FK并删除要解决的违规项目。
如果你有这样的关系:
create table foo_master (
foo_master_id int not null primary key
,current_foo_id int
)
create table foo_detail (
foo_detail_id int not null primary key
foo_master_id int not null
)
alter table foo_master
add constraint fk_foo_current_detail
foreign key (current_foo_id)
references foo_detail
alter table foo_detail
add constraint fk_foo_master
foreign key (foo_master_id)
references foo_master
然后,由于循环依赖性,删除记录会导致这样的鸡和焦点问题。
更好的架构如下所示:
create table foo_master (
foo_master_id int not null primary key
)
create table foo_detail (
foo_detail_id int not null primary key
foo_master_id int not null
is_current char (1)
)
alter table foo_detail
add constraint fk_foo_master
foreign key (foo_master_id)
references foo_master
这意味着该关系是非循环的,并且仍然可以识别“当前”foo_detail记录。
答案 4 :(得分:1)
应像瘟疫一样避免循环引用。可以设置双向关系,甚至可以建立与自己的关系(如果你是一个表),但循环依赖只是要求麻烦。
答案 5 :(得分:1)
我已经看到因性能原因而完成的循环引用。虽然它看起来很丑陋,但性能可能微乎其微。
示例:一些公告牌(我认为phpBB这样做)在类别表中有一个lastpostid,它是线程中最后一篇文章的快捷方式。
这会创建一个圆圈,其中最后一个帖子对类别表有一个FK,而类别表有一个FK回到最后一个帖子。
就像我说的那样,我并不喜欢它,但我已经看过它了。
答案 6 :(得分:0)
我很少遇到必要的1:1关系并且建立了循环关系
请注意,此类关系中的外键字段必须是可空的,否则您永远不能从表中删除行
答案 7 :(得分:0)
如果您使用的是只写数据库,我想这不是问题。如果你计划使用CRUD的RUD部分,你可能会遇到(通常是可以避免的)复杂问题。