Ruby 什么时候不使用规范化数据库是正确的?

Ruby 什么时候不使用规范化数据库是正确的?,ruby,ruby-on-rails-3,activerecord,normalization,Ruby,Ruby On Rails 3,Activerecord,Normalization,情况如下: 假设我有一个狗模型和一个疫苗接种模型(因此,一个表存储了几行狗和一个表存储了给狗接种的几行疫苗) 因此,一只狗有很多种接种疫苗,而一种接种疫苗属于一只狗 我希望能够快速回答这个问题:“狗A最后一次接种疫苗是什么时候?”有两种方法存储这些数据: 1) 规范化数据库方式:让疫苗表存储所有内容。要回答此问题,请在DB中搜索给狗A接种的所有疫苗,并返回最近接种的疫苗 2) 非规范化数据库方式:在Dog中有一个名为“last_vaccination”的字段,并在每次给Dog a接种疫苗时维护该

情况如下:

假设我有一个狗模型和一个疫苗接种模型(因此,一个表存储了几行狗和一个表存储了给狗接种的几行疫苗)

因此,一只狗有很多种接种疫苗,而一种接种疫苗属于一只狗

我希望能够快速回答这个问题:“狗A最后一次接种疫苗是什么时候?”有两种方法存储这些数据:

1) 规范化数据库方式:让疫苗表存储所有内容。要回答此问题,请在DB中搜索给狗A接种的所有疫苗,并返回最近接种的疫苗

2) 非规范化数据库方式:在Dog中有一个名为“last_vaccination”的字段,并在每次给Dog a接种疫苗时维护该字段

#1的优点是:您可以实现数据库规范化,不必担心维护准确的数据

#2的优点是:性能——您不必每次都搜索疫苗数据库


做这件事的正确方法是什么?

就我个人而言,在这种情况下,我意识到的一点是:

如果您发现需要不断地将聚合或“最新记录”信息存储在另一个表中(并打破规范化),主要是为了提高性能,那么您真正需要的是缓存,而不是列/表

选择你的毒药:一个简单的内存缓存,一个分布式缓存,或者是对你的RDBMS的NoSQL补充

在您的特定情况下,最简单的方法可能是:

Rails.cache.fetch("dogs/#{@dog.id}/last_vaccination") do
  @dog.vaccinations.last
end

就我个人而言,在这种情况下我意识到的一件事是:

如果您发现需要不断地将聚合或“最新记录”信息存储在另一个表中(并打破规范化),主要是为了提高性能,那么您真正需要的是缓存,而不是列/表

选择你的毒药:一个简单的内存缓存,一个分布式缓存,或者是对你的RDBMS的NoSQL补充

在您的特定情况下,最简单的方法可能是:

Rails.cache.fetch("dogs/#{@dog.id}/last_vaccination") do
  @dog.vaccinations.last
end

几年前在一次软件研讨会上,我从一个DB的家伙那里听到一句话,我非常喜欢这句话:

“正常化直到受伤,非正常化直到工作。”

这里面有很多道理


FWIW,我认为上面的布局有一个洞——需要有一个“疫苗接种”表,实际上,它将狗与疫苗联系在一起。接种疫苗!=疫苗。这是规范化版本的更精确表示。依我看。

多年前,在一次软件研讨会上,我从一位DB人员那里听到一句话,我非常喜欢这句话:

“正常化直到受伤,非正常化直到工作。”

这里面有很多道理


FWIW,我认为上面的布局有一个洞——需要有一个“疫苗接种”表,实际上,它将狗与疫苗联系在一起。接种疫苗!=疫苗。这是规范化版本的更精确表示。IMO.

这显然是一个非常简单的示例,规范化的原因是每个表中都有特定于主键的数据。我想说的是,您希望尽可能地规范化您的表,否则您将得到一个存储所有数据的绝对庞大的表。这显然是一个非常简单的示例,规范化的原因是每个表中都有特定于主键的数据。我想说的是,只要有可能,您都希望规范化您的表,否则您将得到一个存储所有数据的绝对庞大的表。疫苗接种是一个与狗和疫苗有多对多关系的表格。它至少有4列:id(PK)、dog_id(FK)、vaccine_id(FK)、vaccine_date。@DavidW让我们假设只有一种类型的疫苗。我更新了问题以反映这一点。同意。疫苗接种是一个与狗和疫苗有多对多关系的表格。它至少有4列:id(PK)、dog_id(FK)、vaccine_id(FK)、vaccine_date。@DavidW让我们假设只有一种类型的疫苗。我更新了问题以反映这一点。因此,您的意思是,每次添加新记录时,我仍然必须实现更新缓存的业务逻辑,对吗?您可以使用
@dog.cache\u key
而不是
@dog.id
。它在时间戳处包含更新的_,以确保缓存始终是新鲜的。只要确保每次添加新疫苗时都会更新时间戳:
investment.allows\u to:dog,touch:true
那么您的意思是,每次添加新记录时,我仍然需要实现业务逻辑来更新缓存,对吗?您可以使用
@dog.cache\u键
而不是
@dog.id
。它在时间戳处包含更新的_,以确保缓存始终是新鲜的。只需确保每次添加新疫苗时都会更新时间戳:
invision.allows\u to:dog,touch:true