MySQL 3路1..n表关系

时间:2013-01-14 16:53:28

标签: mysql database database-design relational-database

包含3个表的1个数据库:用户 - 照片 - 投票
- 用户可以拥有许多照片 - 一张照片可以有很多票 - 用户可以对许多照片进行投票 - 投票记录:
。结果为int(-1 / disliked,0 / neutral,1 / likes)
。投票的用户的身份。

这就是我所拥有的(所有FK在删除和更新时都是级联的):
http://grab.by/iZYE
(sid =代理人ID)

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

2 个答案:

答案 0 :(得分:1)

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

假设您只允许每张照片在每张照片上投一票,可以修改其结构,因此唯一的列是user_idphoto_idvote_result。然后,您可以将主键设为(user_idphoto_id)上的复合索引。但是,由于你使用的是外键,这使得这个表格更加复杂。

答案 1 :(得分:1)

MySQL / InnoDB表始终是聚类的(更多关于聚类herehere)。

由于主键也充当集群键 1 ,因此使用代理主键意味着您对表进行物理排序,使其对客户端应用程序没有用处,并且不能用于查询。

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

由于这些原因,您需要避免使用代理并使用更多“自然”键,类似于:

enter image description here

(表{USER_ID, PICTURE_NO}中的VOTE引用PICTURE中相同名称的字段。VOTE.VOTER_ID引用USER.USER_ID。使用*_ID的整数如果可以,请输入1}}和*_NO字段。)

此物理模型将实现极为高效的查询:

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

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


1 在InnoDB中。有DBMS(例如MS SQL Server),其中群集密钥可能与主要密钥不同。

相关问题