4.3 范式和反范式

反范式:

4.3 范式和反范式_第1张图片

Say Brown 接任Accounting 部门的领导,修改多行数据,改成下面(范式):

4.3 范式和反范式_第2张图片
符合第二范式

(Last Name)作为主键,很糟糕:不能保证唯一性,太长

一、范式

优点:

快,重复数据少,只需要修改更少的数据。

表小,更好放内存里,执行操作快。

更少需要DISTINCT或者GROUP BY

缺点:关联,使索引策略无效

二、反范式

避免关联。

当数据比内存大时这可能比关联要快得多,因为这样避免了随机I/O。例:

4.3 范式和反范式_第3张图片

MySQL 需要扫描message 表的published 字段的索引。对于每一行找到的数据,将需要到user 表里检查这个用户是不是付费用户。如果只有一小部分用户是付费账户,那么这是效率低下的做法。

从user 表开始,选择所有的付费用户,获得他们所有的信息,并且排序。更糟糕。

反范式化:两张表字段合并一下,增加一个索引(account_type, published),高效:

4.3 范式和反范式_第4张图片

4.3.3 混用范式化和反范式化

实际经常混用,可能使用部分范式化的schema、缓存表

反范式:复制或者缓存,在不同的表中存储相同的特定列。

在我们的网站实例中,可以在user 表和message 表中都存储 account_type 字段,而不用完全的反范式化。这避免了完全反范式化的插入和删除问题,因为即使没有消息的时候也绝不会丢失用户的信息。这样也不会把 user_message 表搞得太大,有利于高效地获取数据。

但是现在更新用户的账户类型的操作代价就高了,因为需要同时更新两张表。至于这会不会是一个问题,需要考虑更新的频率以及更新的时长,并和执行SELECT 查询的频率进行比较。

另一个从父表冗余一些数据到子表的理由是排序的需要。例如,在范式化的schema 里通过作者的名字对消息做排序的代价将会非常高,但是如果在 message 表中缓存author_name 字段并且建好索引,则可以非常高效地完成排序

缓存衍生值也是有用的。如果需要显示每个用户发了多少消息(像很多论坛做的),可以每次执行一个昂贵的子查询来计算并显示它;也可以在 user 表中建一个 num_messages列,每当用户发新消息时更新这个值。

你可能感兴趣的:(4.3 范式和反范式)