写在前面:本来“程序员应知”系列中应该写的都是与程序员密切相关的内容,而数据库设计似乎应该是数据库管理员的工作。然而,在实际的工作环境中,我所经历几乎所有的项目中,数据库设计工作都是由程序员来完成的;就算我们是不需要做数据库设计的程序员,也至少需要对数据库的结构有充分的理解,那样也便于我们编写和维护系统。思量再三,我还是将这篇与数据库设计相关的文章放在了这个系列当中。
在几乎所有的企业级应用程序中,包括各种MIS、ERP、CRM等等,都会使用数据库,这样的好处是显而易见的,很容易地实现了数据层和业务逻辑层的分离,而且对于性能的优化也在一定程度上提供了便利。
然而,在我所经历过的项目中,某些数据库的设计会存在一些问题,尤其普遍的就是下面将要描述的这两点,个人觉得是应该避免的误区,总结出来与大家讨论。
误区之一
备用字段
现象描述:
在数据表中,不仅设计了当前所需要的字段,而且还在其中留出几个字段作为备用。
比方说,我设计了一个人员表(Person),其中已经添加了各种必要的字段,包括姓名(Name)、性别(Sex)、出生年月日(birthday)等等。大功告成之后,我忽然想到,将来系统中应该还会有很多其它与人相关的内容吧,比方说毕业院校,比方说工作单位等等,尽管现在根本不需要填写,以后可能还是会用到的吧。拍脑袋一项,那就加入5个varchar2型的字段,分别叫做Text1、Text2……Text5,然后又想,应该还有一些日期型的字段需要备用,就又建立了三个date型的字段,分别起名叫做date1、date2、date3,……
原因分析:
大家应该已经看出问题了,在这个数据表中存在大量暂时无用的字段,我们可以称之为备用字段,它们的作用是什么呢?就是以防万一,防备可能的情况。
这似乎可以叫做防患于未然,等到时候需要的时候,就不需要在表中增加新的字段了,而且这样做的话,一个表的数据应该会被存储在相邻的物理空间中,这对于性能也是有好处的。
另外的原因就是,在古老的数据库中,如果改变数据库的定义(包括增加字段、改变字段的类型、删除字段等等),那么其中所有的数据就会丢失,所以这项工作非常麻烦,我们需要先建立临时表,将数据备份出来,然后创建新表,将数据导入其中,最后再删除原来的表。
问题所在:
这样的做法对于项目会导致很多问题,而且原先想要解决的问题并不一定能够解决,不信的话,请往下看。
问题一:增加大量备用字段,必定会浪费很多空间,尽管其中可能都没有具体的数据,但是仅仅是空字段也会占据一定的空间的。
问题二:由于命名的特点,如果没有完善的文档管理流程,用不了多久(可能也就是两三年),就没有人能够说清楚到底哪个字段代表的是什么意义了。就算有文档管理,这些管理工作也会比较麻烦,而且在每次使用的时候都需要申请,还有可能会出现冲突的情况。
问题三:增加了这些备用字段就真的会够用吗?不一定,因为我们只是每个类型的字段留出几个备用,如果数量超过,或者要使用特殊的、不常用的类型的时候,还是需要增加新的字段。比方说在上述的Person表中,我们要存储照片,那么可能就要增加一个blob类型的photo字段,这在初期设计的时候可不一定会留出这样的备用字段。而且如果没有完善的管理,谁又能说清楚倒底哪个字段已经被使用,哪个字段还可以使用呢?到时候还不是要增加新的字段。
解决方案:
其实上面的这种设计方式就是一种“过度设计”,我们应该做的就是“按需设计”,在经过详细有效的分析之后,在数据表中只放置必要的字段,而不要留出大量的备用字段。
当需要增加相关的信息的时候,就要具体情况具体分析:
如果数量很少,而且信息的性质与原表密切相关,那么就可以直接在原表上增加字段,并将相关的数据更新进去。
如果数量较大,或者并非是原表对象至关重要的属性,那么就可以新增一个表,然后通过键值连接起来。
对于表的数据的存储位置所导致的性能问题,我们可以通过在特定时间对数据库的数据进行重组来解决,而这项工作对于长期运行的数据库来说,也是需要定期进行的。
误区之二
有意义的编码
现象描述:
使用有意义的编码作为一条记录的ID,甚至作为数据库的主键存在,例如,一个员工的编码设置为0203004,其中02代表员工所在分公司,03代表员工所在部门,004代表员工进入到该部门的序号。
原因分析:
ID的设置方式大概有以下几种,一种是纯粹的流水号,从1开始,每次加1,或者对其将以改进,将数字转换成为字符串的格式,比方说“0000001”;一种是无意义的随机编码,比方说GUID;还有一种就是有意义的编码,特定的位数会代表一定的意义。
我想之所以大家这么喜欢使用这种方式,主要是因为想要从编码中就能够得到一些信息,甚至有些程序中还有专门的对编码进行解析的模块。就像我们的身份证号码一样,看到身份证号就可以知道办身份证时的所在地、生日、性别等信息。
问题所在:
其实有意义的编码会导致很多问题,请看:
问题一:对编码资源的浪费。如果是纯粹的流水号,那么从1到10000就可以代表一万条记录,但是,如果使用有意义的编码,很可能1000条记录就会让五位的编码不够用。我就遇到过真正的情况,我们公司的投保单号码的第一位就是有意义的,代表的时该投保单所属的渠道,后面跟着很长的一串数字(9位)。理论上来说,这些编码永远都不会用完,但是,最开始的三个渠道使用的是1、4、7三个编码,但是一次新保险法的实行,导致原有的投保单作废,于是又启用了三个数字2、5、8,接下来公司改名,三个渠道又分别将投保单报废,重新启用新的开头数字,就这样,短短的几年间,所有的投保单号码全都被用完了,其实打印出来的投保单不过100万张。
问题二:不一定是唯一的,难以作为主键。想一下,我们的身份证号码就是这样的。原先15位的时候,后三位是序号,而男性会使用奇数,女性会使用偶数,这样就是说,一个地区同一天生日的人,男女都不能超过500人,否则就会导致号码的重复,尽管出现这种现象的概率比较低,但是还是客观存在的。
问题三:代表的意义不一定准确。比方说用带有意义的编码来为员工定义工号,其中可能会有部门、职务等等意义,但是如果员工在部门间发生了调动,或者职级发生了改变,是否需要改变他的编码呢?改变吧,那么所有的历史数据都要随之修改一次,工作量会非常大;不改变吧,那么代表的意义就不再准确,我们就无法从编码中得到该员工准确的信息。
解决方案:
所以,对于编码,非常不建议使用有意义的编码,要么使用纯粹的流水号,但这样可能需要定义一个范围比较大的类型,对于海量记录的数据,可能会不够用;那样的话就可以使用GUID,这样编码永远都不会重复,而且会有大量的编码资源可用。
从上面的两点我们可以看出,在数据库设计的过程中,有一些在非常多系统中都使用了,但是却带来了很多问题的方法,对于这种情况,我们就应该仔细思考,然后痛下决心,坚决抵制。
分享到:
相关推荐
总结了程序员面试中数据库有关的知识点,包括:范式,SQL语言,存储过程.并给出了部分相关的面试题目。
新入行程序员应知的十个秘密
LLVM 程序员手册 —— LLVM 4.0 文档LLVMLLVMLLVMLLVM
浅谈数据库设计技巧,里面详细解说数据库设计方面的技巧,让程序员做数据库设计更灵活处理.
黑马程序员——Android移动开发源码
程序员——必看的文档 程序员——必看的文档 程序员——必看的文档 程序员——必看的文档
《程序员突击——Tomcat原理与Java Web系统开发》源码 作者根据多年的Java Web开发经验,精心编写了本书。按照读者的学习规律,本书在介绍Java技术的基础上,循序渐进地介绍了如何在最新的Tomcat上开发整合各种Java ...
书 名:程序员突击——VISUAL C#2008原理与系统开发 作 者:欧阳炜昊 主编 出 版 社:清华大学出版社 出版时间:2009-8-1 ISBN:9787302183549 纸书页数:352页 定 价:¥ 36.00 内容简介: 本书集...
nacicat 数据库操作工具,程序员必备nacicat 数据库操作工具,程序员必备nacicat 数据库操作工具,程序员必备nacicat 数据库操作工具,程序员必备nacicat 数据库操作工具,程序员必备nacicat 数据库操作工具,程序员...
《MySQL数据库原理、设计与应用》课后习题及答案 黑马程序员编著 答案都是正确的,因为是老师给的资源。 如果不想下载,也可以去我的博客看,一模一样的。 ...
绝对详细的Linux指南,从Linux基础知识开始,直到高级编程,不仅适合Linux程序员,也适用学习Linux的朋友
程序员考试c和数据结构那一部分的习题,题型:填空、选择、编程。
这是我朋友传给我的一个好东西,我和大家分享一下。这里面的java面试题比较全,还有一部分英语面试题。是java程序员成功进入理想工作单位的必看之书,欢迎大家积极下载!
无论是Objective-C语言还是Swift语言,其都有非常巧妙的设计思想与丰富的语法特性。在编写程序时,编程语言是最基础的工具,工具是否用的顺手会直接影响到所编写程序的效率与质量。还有很多时候,一种场景我们知道...
Linux程序员——C语言源代码Linux程序员——C语言源代码
这是一些c语言开发实例,能完善自己的编程思想,让你步入编程员的世界
[12]优秀程序员之路——C++开发经验及技巧大汇总.zip上位机开发VC串口学习资料源码下载[12]优秀程序员之路——C++开发经验及技巧大汇总.zip上位机开发VC串口学习资料源码下载[12]优秀程序员之路——C++开发经验及...
多线程是一种软件实现多个线程并发执行任务的技术。在iOS开发中,实现多线程的的方式有很多种,常用的有pthread、NSThread、GCD与NSOperation。在实际应用中,多线程技术也有着非常多的使用场景,比如异步的网络请求...
这是一个chm格式的中文 C++编程思想 ,看起来效果不错,可供C++开发人员参考,值得珍藏!