程序员应该知道的数据库设计的两个误区

所属分类: 数据库 / 数据库其它 阅读数: 108
收藏 0 赞 0 分享

然而,在我所经历过的项目中,某些数据库的设计会存在一些问题,尤其普遍的就是下面将要描述的这两点,个人觉得是应该避免的误区,总结出来与大家讨论。

误区之一 备用字段

现象描述:

在数据表中,不仅设计了当前所需要的字段,而且还在其中留出几个字段作为备用。

比方说,我设计了一个人员表(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注入之新手入门示例详解

这篇文章仅仅是对SQL注入进行了一个简单的入门知识的讲解,是sql注入的基础篇,有个好的开头能够帮助大家对SQL注入有一个具体清晰的了解和认识。下面来一起看看吧,有需要的可以参考借鉴。
收藏 0 赞 0 分享

sql注入之手工注入示例详解

之前和大家分享了基本的SQL注入的知识,这一篇讲的就是在得知注入点的之后,如何有效地进行脱裤。文章通过示例介绍的很详细,对大家的理解和学习很有帮助,下面来一起看看吧。
收藏 0 赞 0 分享

SQL注入之基于布尔的盲注详解

首先说明的盲注是注入的一种,指的是在不知道数据库返回值的情况下对数据中的内容进行猜测,实施SQL注入。盲注一般分为布尔盲注和基于时间的盲注。这篇文章主要讲解的是基于布尔的盲注。下面来一起看看吧。
收藏 0 赞 0 分享

node-mysql中防止SQL注入的方法总结

大家都知道SQL注入对于网站或者服务器来讲都是一个非常危险的问题,如果这一方面没处理好的话网站可能随时给注入了,所以这篇文章就给大家总结了node-mysql中防止SQL注入的几种常用做法,有需要的朋友们可以参考借鉴。
收藏 0 赞 0 分享

SQL中Having与Where的区别及注意

这篇文章给大家详细的介绍了SQL中Having与Where的区别,以及这两者的注意事项,文中还分享了Having与Where的示例代码,相信对大家的理解和学习很有帮助,感兴趣的朋友们可以参考借鉴,有需要的朋友们可以一起学习学习。
收藏 0 赞 0 分享

浅析sql server 公共表达式的简单应用

本文主要对sql server 公共表达式的简单应用进行介绍,具有一定的参考价值,有需要的可以看下
收藏 0 赞 0 分享

Mybatis查询延迟加载详解及实例

这篇文章主要介绍了Mybatis查询延迟加载详解及实例的相关资料,Mybatis的延迟加载默认是关闭的,即默认是一次就将所有的嵌套SQL一并查了将对象所有的信息都查询出来。开启延迟加载有两种方式,需要的朋友可以参考下
收藏 0 赞 0 分享

SQL注入详解(扫盲篇)

刚进公司的时候,研究的主要是SQL注入,因为之前没有搞过安全,所有费了好长一段时间对SQL注入基本知识进行了解。所以这篇文章并不是什么很深入的技术博客,或许应该叫它‘ SQL注入扫盲 ’有需要的朋友可以参考学习,下面来一起看看吧。
收藏 0 赞 0 分享

SQL注入绕过的技巧总结

这篇文章主要给大家总结了一些关于SQL注入绕过的技巧,其中包括引号绕过、逗号绕过以及比较符(<,>)绕过,文中给出了详细的介绍和示例代码,相信对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
收藏 0 赞 0 分享

利用reverse索引优化like语句的方法详解

这篇文章主要介绍了关于利用reverse索引优化like语句的方法,文中通过图文介绍的很详细,相信对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。
收藏 0 赞 0 分享
查看更多