我定义了一些数据库表,大致如下所示:
为了快速运行查询,按时间顺序检索Person
MailMessages
,无论发送的MailAccount
是什么,我都想要一个索引对于MailMessage表,按(PersonId,ReceivedTime)排序。这意味着将一个冗余的PersonId列添加到MailMessage表中,如下所示:
......或者是吗?这样做有什么更简洁的方法吗?如果不是,最好的做法是将PersonId作为MailMessage表中的外键,或者不应该这样做,因为它在概念上不是外键,而只是用于(PersonId,ReceivedTime)索引的列?
答案 0 :(得分:2)
您正在做的事情称为denormalization。对这个概念的利弊进行全面讨论对于SO来说有点多了。
使用Materialized View(在SQL Server中称为索引视图)也可以进行此类优化。
答案 1 :(得分:2)
是的,你可以这样做,但需要在MailAccount
上的表{MailAccountId, PersonId}
中使用密钥,因此表MailMessage
中的FK可以引用它。从强制执行唯一性的角度来看,这是多余的,因为仅{MailAccountId}
已经是唯一的。
还有另一种方法:使用识别关系和自然键。例如:
这实现了基本相同的目标,但每个表只有一个键(和底层索引)。
请注意底部表格中PK字段的顺序:它允许查询...
SELECT *
FROM MailMessage
WHERE PersonId = ?
ORDER BY ReceivedTime
...通过主索引上的索引范围扫描得到满足。如果表恰好是clustered,那么DBMS甚至不必在那之后访问表堆(根本没有表堆 - 行直接存储在B-Tree中)。
在不使用冗余密钥(这也适用于群集)的情况下避免JOIN是自然密钥与代理密钥的优点之一。你可以想象,list of pros and cons并没有结束。