MySQL 3路1..n表关系

MySQL 3路1..n表关系,mysql,database,database-design,relational-database,Mysql,Database,Database Design,Relational Database,1个数据库,包含3个表:用户-照片-投票 -一个用户可以有许多照片。 -一张照片可以有很多选票。 -用户可以对多张照片进行投票。 -A投票记录: . 结果为int(-1/不喜欢,0/中性,1/喜欢) . 投票用户的id。 以下是我所拥有的(所有FK在删除和更新时级联): (sid=代理项id) 我的问题是:这似乎不对,我已经看了两天了,不能自信地继续前进。我怎样才能优化它,或者我完全错了?我看到的第一件事是,表上有重复的唯一ID。您不需要sid列;只需使用user\u id、photo\u id

1个数据库,包含3个表:用户-照片-投票
-一个用户可以有许多照片。
-一张照片可以有很多选票。
-用户可以对多张照片进行投票。
-A投票记录:
. 结果为int(-1/不喜欢,0/中性,1/喜欢)
. 投票用户的id。

以下是我所拥有的(所有FK在删除和更新时级联):

(sid=代理项id)


我的问题是:这似乎不对,我已经看了两天了,不能自信地继续前进。我怎样才能优化它,或者我完全错了?

我看到的第一件事是,表上有重复的唯一ID。您不需要
sid
列;只需使用
user\u id
photo\u id
photo\u user\u id
(可能将此项重命名为
vote\u id
)。这些ID列也应该是
INT
类型,绝对不是
VARCHAR
s。您可能不需要
photo
上的投票总数列;您只需在需要时运行一个查询即可获得总数,而无需担心两个表是否保持同步


假设您只允许每个用户在每张照片上进行一次投票,则可以修改的结构,以便仅列为
user\u id
photo\u id
vote\u result
。然后将主键作为(
user\u id
photo\u id
)的复合索引。但是,由于您使用的是外键,这使得这个表有点复杂。

MySQL/InnoDB表总是集群的(更多关于集群和数据库)

由于主键还充当集群键1,因此使用代理主键意味着您正在按对客户机应用程序没有有用意义且无法用于查询的顺序对表进行物理排序

此外,聚集表中的二级索引可能比基于堆的表中的二级索引“更胖”,并且可能需要双重查找

出于这些原因,您可能希望避免使用代理并使用更“自然”的键,类似于:

{USER\u ID,PICTURE\u NO}
表中的
投票
引用了
图片
中相同的命名字段。
投票.投票人ID
引用了
用户.用户ID
*\ID
*\NO
字段使用整数,如果可以的话。)

此物理模型将实现对以下各项的高效查询:

  • 给定用户的图片(对
    PICTURE
    primary/clustering索引进行简单的范围扫描)
  • 对给定图片进行投票(对
    VOTE
    primary/clustering index进行简单的范围扫描)。根据具体情况,这实际上可能足够快,因此您不必将总和缓存在
    图片中
如果您需要给定用户的投票,请将
投票
主键更改为:
{VOTER\u ID,user\u ID,PICTURE\u NO}
。如果同时需要(图片投票和用户投票),保留现有PK,但在
{VOTER\u ID,user\u ID,picture\u NO,VOTE\u VALUE}
上创建索引



InnoDB中有1个。有些DBMS(如MS SQL Server)的群集键可以不同于主群集键。

什么(或谁)是“sid”?在我看来,你就快到了——一张用户表(用户id*)、一张照片表(照片id*)和一张投票表(用户id*、照片id*、投票)。[*=(component of)PRIMARY KEY.sid=代理id(auto increment index PK)[Vote]不应该只对投票的用户对照片的“所有者”使用FK,因此照片用户sid是多余的。这有帮助吗?让我困惑的是用户照片(1..n)和照片投票(1..n),而用户投票也是(1..n)(屏幕截图)@CHill60-hmm实际上是由MySQL Workbench GUI工具完成的…实际上所有的'sid'都是代理主键。'user_id'是uniqid()生成的,带有“photo_id”的,保存以供以后使用。它们不是键。“photo_user_id”是由MySQL Workbench在1..n从“photo”到“vote”时生成的,它不是“vote_id”,这是“vote”表的“sid”。我不确定“代理主键”是什么意思,但您不应该需要它们。它们在原始模式中的使用方式是作为每个表的唯一ID,使得
user\u ID
列无效。为什么表中的每一行都需要一个额外的唯一ID?在stackove上遇到这个巨大的争论之前,我一直在考虑代理键的问题rflow()我认为这是有道理的。为什么我在本地android sqlite db中使用额外的唯一id,这是我正在玩的项目的另一面。@jerrytouille所以我读了这个问题,我同意我读到的内容:如果普通的唯一键是复杂/复合的,代理键是有用的,但是如果普通的唯一键是s的,代理键基本上是无用的imple类似于
INT
。据我所知,架构中唯一可以受益于代理项键的表是
vote
表,但由于潜在代理项ID永远不会引用它,因此没有理由这样做。至于主表,如果使用
INT
作为唯一键,我们就没有理由这样做e一个代理ID。除了最后一句让我有点困惑的话,我得到了所有的u。代理ID(sid)确实被用作所有表中的主唯一键。“用户ID”和“照片ID”是为我以后的需要而生成的VARCHAR和uniqid()。您如何“使主键成为(用户ID,照片ID)上的复合索引?”通过“在{VOTER_ID,USER_ID,PICTURE_NO,VOTE_VALUE}上创建覆盖索引”来替代FKs您的意思是添加一个自动递增索引,但使其不是PK,对吗?@jerrytouille这与值的生成方式无关,而是与索引中包含哪些字段有关。常规索引将包括WHERE/JOIN中提到的字段,但覆盖索引也将包括SELECT列表中提到的字段。这将让DBMS执行仅通过访问索引进行查询,而不接触“m”