我们在这里假设 认为遵守数据库设计的范式,不要冗余 的为正方:
认为设计数据库设计需要设计一些适当冗余的为 反方:
希望大家能结合自己设计经验,展开积极的讨论:
下面是我举的一个例子:
比如做一个单据表,主要字段
单号 商品编号 商品名称 单价 数量
正方:
单据表只能有“ 单号 商品编号 单价 数量 ”这几个字段,
没有“商品名称 ”这个字段,要显示这个信息,就需要和 “商品基本信息表” 关联获取;
反方:
如果 这里的“商品基本信息表 ”里如果有100万条记录,那么我每做一个单据,单据明细信息都需要通过和100万条记录的“商品基本信息表 ”关联,显然,这样软件运行效率肯定要受到影响。
而且 ,写sql语句只关联一个表总比关联多个表更方便。
正方:
如果客户在使用过程中,商品名称发生了改变,那么那些历史单据上的商品名称就会跟着变化,这样能保证数据的一致性;否则,数据在统计的时候,明明是一个商品的入库情况,就会被当成两个或多个,月末结算的时候就会有问题。
反方:
1、“商品基本信息表 ”的“商品名称”本来就不允许轻易改变。如果该商品参与了单据处理,“商品名称”就不应该修改。
2、如果“商品名称”修改了,那么修改前和修改后的单据对于同一个“商品编号”本来就应该显示不同的“商品名称”;就像一个人,如果他在50岁以后该名字的话,那么它50岁前作的事情,我们也应该用他的原名啊。
3、如果正方认为“商品名称”可以修改,那么“商品编号”也可以修改喽。但是
你是通过“商品基本信息表 ”的“商品编号”作为关联的。“商品编号”一旦修改,那么单据明细由于找不到以前的“商品编号”,记录就会丢失。这不是出大乱子。
当然,你会说“商品编号”是商品信息的唯一识别;
但是,为什么不能把“商品名称”最为唯一识别呢。
我们不防看看用户更改“商品名称”的原因是什么? 其实 “商品名称” 往往是相对固定,而“商品编号”反而会因为当初的是设计不合理,而做更改;
比如,一个中学生,他本来的编号是35 ,后来学校改革。把他的编号该成 9831
他的编号变了,但是他的名字却不会变。如果我用冗余,就不会影响该学生在学校食堂的消费历史纪录;
正方:
如果按照反方的观点,为何需要“商品编号”,不如在“商品信息表”里就有一个“商品名称”不就完了;中学生,也不用学号,直接用姓名识别。
首先,“商品编号”或“学生学号”是有意义的。最简单的,“商品名称”或“学生姓名”可能重复;但是利用编号就能容易识别;
如果用户需要更改编号,那么我们可以在每个表里做个内部的id字段,该字段自增长,各个表需要关联时,都是通过他们的id来关联。
这样即使修改了编号也无所谓。
反方:
使用内部id的方法,会大大加大软件的代码编写的复杂度。尤其是报表系统里,为了获取某个特定的信息会写出很复杂的sql,就算你用视图,道理也是一样的,因为写视图也很费力。而且有时复杂的视图的错误隐藏的很深。
再说,比如那个中学生从初一上到高三,突然老师那天不小心把他的学号和姓名都修改了,那么那些在食堂里消费的历史纪录相应的信息修改了。结果想还原都没有办法。
如果我们用冗余,就不存在这个问题。
+++++++++++++++++++++++++++++++++++++++++++++++
数据库冗余:存储两倍数据,冗余可以使系统速度更快。(减少联查)
个人理解:
在设计数据库时,某一字段属于一个表,但它又同时出现在另一个或多个表,且完全等同于它在其本来所属表的意义表示,那么这个字段就是一个冗余字段。
至于冗余字段的存在到底是好还是坏呢?
这是一个不好说的问题。可能在有人看来,这是一个很蹩脚的数据库设计。因为在数据库设计领域,有一个被大家奉为圭臬的数据库设计范式,这个范式理论上要求数据库设计逻辑清晰、关系明确。
比如,”用户昵称”字段”nickname”本来属于表”user”,那么,表示”用户昵称”的字段就唯一的只应该属于”user”表的”nickname”字段,这样,当用户要修改昵称的时候,程序就只需要修改 user.nickname这个字段就行了,瞧,很方便。不过问题也随之而来,我在其他数据表(如订单orders表)里只存储了用户的ID,我要通过这个ID值得到用户昵称该怎么办呢?一个普遍的解决方法是通过联接(join),在查询时,通过id这个唯一条件联接两个表,从而取到用户的昵称。
这样确实是没问题,我也一直觉得这样是最好的方案,扩展方便,当要更新用户信息时,程序中要修改的地方很少,但是随着数据库里数据不断增加,百万,千万,同时,用户表的数据肯定也在不断的增加的,它可能是十万,百万。这个时候,你会发现两个表通过联接来取数据就显得相当费力了,可能你只需要取一个nickname这个用户昵称属性,你就不得不去联一下那个已经几十万的用户表进行检索,其速度可想而知了。
这个时候,你可以尝试把nickname这个字段加到orders这个订单表中,这样做的好事是,当你要通过订单表呈现一个订单列表时,涉及用户的部分可能就不需要再进行联接查询了。当然,有利就有弊,这样做的弊端就是,当你尝试更新用户信息时,你必须记得用户信息表里当前被更新的字段中,有哪些是冗余字段,分别属于哪些表,找到他们,然后加入到你的更新程序段中来。这个是程序中的开销,开销在开发人员的时间上了。至于这样做是否值得,就得看具体情况而定了。
所以,目前要创建一个关系型数据库设计,我们有两种选择:
1,尽量遵循范式理论的规约,尽可能少的冗余字段,让数据库设计看起来精致、优雅、让人心醉。
2,合理的加入冗余字段这个润滑剂,减少join,让数据库执行性能更高更快。
选择哪一种呢?如果你是一个美学狂人,并且财大气粗,非要使用第一种方案,也没关系,这种方案的短板并非不可救药的。比如,你可以增加服务器,从数据库集群入手,进行读写分离,读的时候可以将压力分散到不同的数据库服务器上,这样也可以获得很好的性能,只是多付出了硬件成本和维护成本。或者,你可以在数据库前端架设Memcached之类的缓存服务,减少读写数据库的次数,也可以达到同样的效果。问题在于你确定你需要缓存之类的东西。
如果做不到上面的只能选择第二种了,当涉及到修改的时候就需要将所有相关的数据进行修改了。
空间换取时间,到底值不值得,看业务需求与取舍了。