违背数据库第三范式引发的一个问题

数据库第三范式的界说,是这样的:

A table is in a third normal form when the following conditions are met -

  1. It is in second normal form.
  2. All nonprimary fields are dependent on the primary key.

简略翻译过来,便是说:

一张恪守第三范式的数据库,应该契合以下两个条件:

  1. 这张恪守第二范式。
  2. 这张中,一切非主特点都(仅)依靠于主特点。

也便是“在第二范式的基础上,消除了非主特点对主特点的传递依靠”。

ps,尽管咱们在建表时运用的主键大多是事务无关的字段(例如自增主键),可是在评论数据库范式时,“主特点”、“非主特点”一般都是指的事务字段。不然,恐怕没有一张表是契合第二范式的,更遑论第三范式了。

<hr/>

网上对第三范式的举例说明可谓举目皆是,这儿就不赘述了。

我这儿要举的比如有点特别。它不只仅在表中引入了传递依靠,乃至还隐去了传递依靠的中间环节。

简略一点来说,这张表是这样的:

CREATE TABLE TB_CONTACTER(
ID            INT              NOT NULL    AUTO_INCREMENT,
USER_ID       INT              NOT NULL,
CHANNEL_ID    VARCHAR(10),
CONTACTER     VARCHAR(100),
PRIMARY KEY (ID),
KEY(USER_ID,CHANNEL_ID)
);

这张表的最大问题在于:CONTACTER并不是直接依靠于USER_ID+CHANNEL_ID的。它们之间存在着这样的一种传递依靠:
USER_ID+CHANNEL_ID --> USER_ID+PRODUCT_ID --> APPLY_ID --> CONTACTER。

翻译一下便是这样的,用户从某个途径进入体系,挑选一个产品,提交一笔请求,并给这个请求单指定一个收货的联系人。

这个依靠的确有点杂乱。所以,这张表的规划者对它做了一个简化处理。

依照其时的事务束缚,一个用户在一个途径上,都只能挑选一个产品;针对每个产品都提交一笔有用请求;而这笔请求单上,只能指定一个联系人。用图形来表明便是这样的:

违背数据库第三范式引发的一个问题

已然这个依靠链是如此地一根筋,那咱们就一竿子捅究竟好了。所以,就有了前面的TB_CONTACTER表的规划。

<hr/>

可是,事务数据之间的依靠联系是由产品需求界说的。而只需数一数产品司理有多少次拍胸脯确保“这次的需求不会再改了”,咱们就知道产品需求有多善变。

在如此善变的产品需求面前,让事务数据之间的依靠联系永久坚持不变,真是一种奢求。

而这种不切实际的奢求,很快就让咱们尝到了苦头。

不知道该说果然如此仍是该说大出所料,赖以简化依靠联系的事务束缚被后来的产品需求打破了,终究——应该说是现在——变成了这样:

一个用户不只可以在多个途径上请求同一个产品;并且在每一个途径上,都可以挑选多个产品、提交多笔有用请求;不过每一笔请求单上,依然只能指定一个联系人。

相同用图来表明,便是这样的(留意最左面的数据联系,从原先的1:1变成了N:M):

违背数据库第三范式引发的一个问题

所以乎,咱们的这张TB_CONTACTER表就呈现了一个问题:无论是依据USER_ID+CHANNEL_ID,仍是依据APPLY_ID,咱们都无法精确地查到请求单上相关的联系人了。

假如不做改造,这张表等所以废了。而真的改造起来,里边有几百上千万的存量数据,怎样处理都让人头大。

<hr/>

总结一下来说,尽管数据库范式算得上很“陈旧”的技能思维,可是俗话说得好,姜是老的辣,酒是陈的香。可以阅历大浪淘沙、沉积至今的技能,依然值得咱们仔细研究和谨慎运用。

<hr/>

违背数据库第三范式引发的一个问题