繁体   English   中英

规范化或不规范化user_id

[英]To normalize or not to normalize user_ids

在我的Rails应用程序中,我有各种包含用户数据的数据库表。 其中一些表有很多行(在某些情况下每个用户多达500,000行)并经常查询。 每当我查询任何表时,当前用户的user_id就在查询中的某个位置 - 直接,如果表与用户有直接关系,或者通过连接,如果它们通过其他表相关联。

我应该对user_id进行非规范化并将其包含在每个表中,以获得更快的性能吗?


这是一个例子:

  • 地址属于用户,并具有user_id
  • 信封属于用户,并且具有user_id
  • AddressesEnvelopes连接一个地址和一个信封,因此它有envelope_id和address_id - 它没有user_id,但可以通过信封或地址(必须属于同一个用户)来访问它。

一个常见的昂贵查询是选择特定用户的所有AddressesEnvelopes,我可以通过加入Address或Envelope来完成,即使我不需要这些表中的任何内容。 或者我可以在此表中复制用户ID。


这是一个不同的场景:

  • 字母属于用户,并具有user_id
  • Recepient属于Letter,并且有一个letter_id
  • RecepientOption属于Recepient,并且具有recepient_id

在Recepient和RecepientOption中复制user_id是否有意义,即使我总是可以通过关联通过Letter来获取它?


一些说明:

  • 用户之间永远不会共享任何对象。 相关对象的整个层次结构始终属于同一用户。
  • 对象的用户所有者永远不会更改。
  • 数据库性能很重要,因为它是一个数据密集型应用程序。 有许多查询和许多表。

那么我应该在每个表中包含user_id,以便在创建索引时可以使用它吗? 或者那是不好的设计?

我想指出,如果您愿意使用复合主键,则无需非规范化。 AddressEnvelop案例:

user(
    #user_id
)
address(
    #user_id
,   #addres_num
)
envelope(
    #user_id
,   #envelope_num
)
address_envelope(
    #user_id
,   #addres_num
,   #envelope_num
)

(#表示主键列)

如果我可以避免它,我不是这个设计的粉丝,但考虑到你说所有这些对象都绑定到用​​户这一事实,这种类型的设计会使得对数据进行分区相对简单(逻辑上,放置范围)用户在单独的表中或物理上,使用多个数据库甚至机器)

使用这种类型的设计有意义的另一件事是使用聚簇索引(在MySQL中,InnoDB表的主键是从聚簇索引构建的)。 如果确保user_id始终是索引中的第一列,则它将确保对于每个表,一个用户的所有数据都紧密地存储在磁盘上。 当你总是按user_id查询时这很好,但是如果你用另一个对象查询它会损害性能(在这种情况下,像你想要的重复可能是一个更好的解决方案)

无论如何,在更改设计之前,首先要确保您的架构已经过优化,并且您的外键列上有适当的索引。 如果性能确实至关重要,那么您应该尝试几种解决方案并进行基准测试。

只要你

a)获得可衡量的性能改进

b)知道数据库的哪些部分是真实的标准化数据,哪些部分是冗余的改进

没有理由不这样做!

你真的有一个测量性能问题吗? 50万行表不是很大。 如果选择不是很复杂并且列上有适当的索引,那么您的选择应该是合理的。

我首先会看到是否有慢查询并尝试使用索引优化它们。 如果这还不够,那么我才会考虑非规范化。

如果您无法通过其他方式获得所需的性能,那么您建议的非规范化似乎是合理的。 只需确保将非规范化字段保持最新。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM