前言

在讲范式和反范式之前,首先先搞清楚什么是范式!如下

第一范式

每个表的每一列都要保持它的 原子性 也就是表的每一列都是不可分割的

MySQL范式和反范式_字段


修改后

MySQL范式和反范式_数据_02


第二范式

要在满足第一范式的基础上,每个表都要保持 唯一性 也就是表的非主键字段要完全依赖主键字段。

MySQL范式和反范式_数据_03


MySQL范式和反范式_第一范式_04

第三范式

要在满足第一和第二范式的基础上,表中不能产生传递依赖,要消除表中的冗余性

MySQL范式和反范式_字段_05

范式

范式优点

  1. 范式化的更新操作通常比反范式操作要快
  2. 当数据较好的范式化时,就只有很少或者没有重复数据所以只需要修改更少的数据
  3. 范式化的表通常很小,可以更好的放在内存中,所以执行操作会更快
  4. 很少有多余的数据意味着检索列表数据时更少需要DISTINCT或者GROUP BY语句

范式缺点
范式话通常需要关联,稍微复杂一些的查询语句在符合范式上可能需要至少一次关联,或许更多,这不但代价昂贵,也可能是的一些索引策略失效!例如:​​​范式化可能将列放在不同的表中,而这些列如果在一个表中本可以属于同一个索引!​

反范式

反范式话数据都在同一张表中,这样可以很好的避免表关联,这样可以避免导致索引失效的一些问题,单表可以使用更有效的索引策略,例如:有个网站,允许付费用户发消息,现在先查看付费用户发送的最近10条消息,如果范式话的结构并且索引了发送日期字段published,这个查询也许看起来像这样

SELECT message_text ,user_name FROM message
INNER JOIN user ON message.user_id=user.id
WHERE user.account_type='premiumv'
ORDERBYmessage.published DESC LIMIT 10;

更有效的执行这个查询,MySQL需要扫描message表中的published字段的索引,对于每一条匹配到的数据都需要到user表里检查这个用户是不是付费用户,如果只有一小部分用户是付费用户,那么这是效率底下的做法,如果采用反范式的话,将两张表的字段合并下,并且增加一个索引(account_type,published),就可以不通过关联写出这个查询,如下

SELECT message_text,user_name FROM user_message
WHERE account_type
ORDER BY published DESC
LIMIT 10;

混用范式和反范式

事实上完全范式和反范式这种设计,只有实验室里才有的,在实际应用中通常会混用,可能使用部分范式话的设计,缓存表,以及其他技巧。