2013-01-14 52 views
2

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

这里是我有什么(所有FKS是在删除和级联更新):
http://grab.by/iZYE
(SID =替代ID)

我的问题是:这看起来不正确的,我已经看了2天了,不能自信地继续前进。我如何优化这个或者我完全错了?

+0

什么(或谁)是“sid”?在我看来,你差不多在这里 - 一张用户表(user_id *),一张照片表(photo_id *)和一张投票表(user_id *,photo_id *,vote)。 [* =(PRIMARY KEY的组件)。 – Strawberry

+0

sid =代理id(自动增加索引PK) – jerrytouille

+0

[投票]不应该需要一个FK给照片的“所有者”,只是给投票的用户,所以photo_user_sid是多余的。这有帮助吗? – CHill60

回答

1

MySQL/InnoDB表总是集群(更多关于集群herehere)。

由于主键还充当集群密钥,使用代理主键意味着您在物理上对表进行排序,以便对客户端应用程序没有用处,并且无法用于查询。

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

由于这些原因,你会希望避免代理人和使用更多的“自然”键,与此类似:

enter image description here

{USER_ID, PICTURE_NO}VOTE引用在PICTURE同名领域。VOTE.VOTER_ID参考文献USER.USER_ID。如果可以,请使用*_ID*_NO字段的整数。)

这种物理模型将使极有效查询:

  • 给定用户的图片(在PICTURE初级/集群索引的简单范围扫描)。
  • 给定图片上的投票(VOTE主/集群索引上的简单范围扫描)。根据具体情况,这可能实际上已经足够快,因此您不必在PICTURE中缓存总和。

如果您需要给定用户的投票,请将VOTE PK更改为:{VOTER_ID, USER_ID, PICTURE_NO}。如果您同时需要(图片投票和用户投票),请保留现有的PK,但在{VOTER_ID, USER_ID, PICTURE_NO, VOTE_VALUE}上创建一个covering索引。


在InnoDB中。有一些DBMS(如MS SQL Server),其中集群密钥可能与主节点不同。

+0

通过“在{VOTER_ID,USER_ID,PICTURE_NO,VOTE_VALUE}上创建覆盖索引”,您的意思是添加一个自动增量索引,但将其设置为不是PK,对吧? – jerrytouille

+0

@jerrytouille这与生成值的方式无关,但索引中包含哪些字段。常规索引将包括WHERE/JOIN中提到的字段,但覆盖索引将包括SELECT列表中提及的字段。这将让DBMS通过访问索引_alone_来执行查询,而不用接触“主”表(对于InnoDB,它可以是表堆或B树)。请按照我提供的链接进行详细解释。最后,您将拥有PK'{USER_ID,PICTURE_NO,VOTER_ID}'_and_索引'{VOTER_ID,USER_ID,PICTURE_NO,VOTE_VALUE}'。 –

+0

嗯,这很酷,有点出我的联盟,所以它需要一段时间沉入。如果我正确理解你的整个事情的答案:消除所有代理id(自动增加指数)PKs,使用真正的商业PKs(' user_id','photo_id'...),唯一使用的索引是VOTE表的{VOTER_ID,USER_ID,PICTURE_NO,VOTE_VALUE}上的覆盖索引。我的问题是:当我们设计它时,我们是否创建了覆盖索引作为额外的列添加到表中,或者是我们在运行查询时做什么? – jerrytouille

1

我看到的第一件事是您在表格上有重复的唯一ID。您不需要sid列;只需使用user_id,photo_idphoto_user_id(也许将其重命名为vote_id)。这些ID列也应该是INT类型,绝对不是VARCHAR s。您可能不需要photo上的总票数;您只需运行一个查询即可在需要时获取总数,而不必担心两个表保持同步。

假设您只允许每个用户在每张照片上投一票,则可以修改该结构,以便唯一的列是user_id,photo_idvote_result。然后,您将使主键成为一个组合索引(user_id,photo_id)。但是,由于您使用的是外键,这使得这个表格更复杂一些。

+0

实际上所有'sid'都是代理主键。 'user_id'是生成的uniqid(),'photo_id'被保存以供以后使用。他们不是钥匙。 'photo_user_id'由MySQL Workbench在1..n从'photo'到'vote'时生成,它不是'vote_table''sid'的'vote_id'。 – jerrytouille

+0

我不确定你的意思是“代理主键”,但你不应该需要它们。它们在原始模式中的使用方式与每个表的唯一ID一样,使'user_id'列无用。为什么你需要表格中每一行的附加唯一ID? –

+0

我在想关于代理键的同样的事情,直到我遇到这个巨大的参数在这里stackoverflow(http://stackoverflow.com/questions/63090/surrogate-vs-natural-business-keys),我认为这是有道理的。为什么额外的唯一ID我用它为我的本地android sqlite数据库,这是我玩的项目的另一端。 – jerrytouille