【问题标题】:SQL: Avoid circular dependenciesSQL:避免循环依赖
【发布时间】:2012-02-15 18:44:05
【问题描述】:

我看到大多数人只是讨厌在数据库设计中存在循环依赖。由于在大多数数据库引擎中对此的支持是“棘手的”,我想知道是否有办法绕过这种设计:

我有一个用户表和一个图片表

每张图片都有一个userId(插入它的用户) 每个用户都有一张头像

我可能只是创建一个 ProfilePictures 表,但它会在其他一些地方(如图片 cmets)引起问题。

我知道还有一些其他问题与此问题相关,但它们与父子关系更相关,这里不是这种情况。

那么,这里可以使用循环依赖吗?如果没有,你会如何避免?

【问题讨论】:

  • 所以,一个用户可以插入很多图片。图片仅由一个用户插入。并且用户(可能)有一张个人资料图片(或没有)。对吗?
  • 我不会使用循环依赖,除非绝对没有其他方法可以做到这一点。在 25 多年的数据库工作中,我从未见过没有其他选择的案例。大多数人没有想到的一个问题(直到为时已晚)是循环依赖破坏了许多第三方工具,例如 CASE、图表和逆向工程工具。

标签: sql database-design circular-dependency


【解决方案1】:

表之间没有循环引用:

User 
------
userid NOT NULL
PRIMARY KEY (userid)

Picture
---------
pictureid NOT NULL
userid NOT NULL
PRIMARY KEY (pictureid)
UNIQUE KEY (userid, pictureid)
FOREIGN KEY (userid)
  REFERENCES User(userid)

ProfilePicture
---------
userid NOT NULL
pictureid NOT NULL
PRIMARY KEY (userid)
FOREIGN KEY (userid, pictureid)        --- if a user is allowed to use only a
  REFERENCES Picture(userid, picture)  --- picture of his own in his profile

FOREIGN KEY (pictureid)                --- if a user is allowed to use any 
  REFERENCES Picture(picture)          --- picture in his profile

此设计与您的需求的唯一区别是用户可能没有与其关联的个人资料图片。


表之间的循环引用:

User 
------
userid NOT NULL
profilepictureid NULL                  --- Note the NULL here
PRIMARY KEY (userid)
FOREIGN KEY (userid, profilepictureid)   --- if a user is allowed to use only a
  REFERENCES Picture(userid, pictureid)  --- picture of his own in his profile

FOREIGN KEY (profilepictureid)           --- if a user is allowed to use any 
  REFERENCES Picture(pictureid)          --- picture in his profile

Picture
---------
pictureid NOT NULL
userid NOT NULL
PRIMARY KEY (pictureid)
UNIQUE KEY (userid, pictureid)
FOREIGN KEY (userid)
  REFERENCES User(userid)

profilepictureid 可以设置为NOT NULL,但是当您想要插入两个表时,您必须处理先有鸡还是先有蛋的问题。这可以解决 - 在某些 DBMS 中,如 PostgreSQL 和 Oracle - 使用延迟约束。

【讨论】:

  • 谢谢,其实第二个就是我现在的设计。而且我可以只添加 ProfilePictures 表,但这不会解决循环依赖的问题(即我不能删除用户而不删除图片,我不能删除图片而不删除用户,所以它基本上与拥有两个表,并允许用户中的 profilepictureid 为 null)
  • 我的第一种方法没有循环依赖。
  • 在第二个系统中,如果Picture(PictureID)是主键,那么Picture(UserID, PictureID)的组合也不得不是唯一的。您似乎坚持认为用户不能拥有他们没有插入的个人资料图片 - 这可能是意图。
  • @JonathanLeffler:我坚持使用这个唯一键,主要是因为当您引用没有定义唯一键的组合时,MySQL 似乎不高兴。它可能在其他 DBMS 中工作正常(当主键只是引用组合的一部分时,隐含唯一性)。
  • 但是你是对的,我假设用户不能拥有他们没有插入的个人资料图片。也许这不是OP的意图。然后应该更改引用。不错的发现。
【解决方案2】:

如果每个用户只存储几张图片,您可以在图片中添加一个标志,说明图片是否为个人资料图片。

【讨论】:

  • 这种方法的主要问题是用户可能有多个图片设置为个人资料图片! (有时可以使用条件约束或空值来避免)
【解决方案3】:

用户拥有 UserID 和 ProfilePictureID

图片

有一个PictureID、一个图片和一个UserID

删除用户及其个人资料图片将/可以通过 PictureID 删除,如果需要,还可以通过用户 ID 删除任何其他图片。

甚至不要这样考虑这个通告。

【讨论】:

  • “不考虑这个通告”是什么意思?我遇到的问题是不删除图片就不能删除用户,不删除用户就不能删除图片。
  • 好吧,如果您在我回答时发布了您的架构,我会看到的。这不是我会做出的设计决定,它会导致您看到的问题。 :)
猜你喜欢
  • 2013-02-06
  • 1970-01-01
  • 2012-08-10
  • 1970-01-01
  • 1970-01-01
  • 2013-04-02
  • 2011-06-16
  • 2023-03-11
相关资源
最近更新 更多