前言
数据库是软件数据的核心部分,也可以说是软件的心脏部分,好的数据库设计会让软件具有较高的扩展性,以及很好的性能,差的数据库设计会大大缩短软件的生命周期,甚至直接导致软件上线不久就死亡。下面我就以我现在的经验,说一说,如何去设计一个好的数据库。
表命名和字段命名
表命名和字段命名要注意地方是:
一、命名不要使用中文,因为中文的编码是GB2312或者GBK,但现在主流的数据库,如MySql,Oracle,SqlServer默认编码都是UTF-8,如果为了途方便而使用中文,就避免不了要解决乱码问题。
二、命名不建议和系统函数或关键字重名,因为你写SQL语句的时候通常都不会加表示列名或者字段名的转义符号,而如果你的表命名或者字段命名与系统函数或关键字重名,就会出现SQL运行的错误,而你又要费时间去找,找完还要把转义符都加上,非常麻烦。
三、命名不要用拼音首字母,命名千万不要用拼音首字母,使用英文或者拼音全拼,因为这会使得别人很难读得懂你字段的意思,我曾经就看过一个数据库,里面字段全是这种简拼,非常难读懂,姓名就写XM,身份证号就写SFZH,学号就写XH,一个,两个,三个,那还受得了,整个数据库一百多个字段都这样,而且还不带重样的,基本就吐血了。
字段类型定义
字段类型定义需要注意的地方是:
一、字段长度尽量设置的比估计的长度稍微大一些,特别是在定义varchar字符串类型的时候,最好是估计长度的100%~120%,因为在实际开发过程中,一定会遇到需求不断变更,或者出乎意料之外的情况,如果你在此之前做过一些准备,那么即使出现意外了,你就能非常轻松的应对了。当然这种设置不能太大,比如像varchar这种,虽然是可变长度的字符串,但是如果设置太大,是会影响查询性能的。
二、合理使用固定长度字符串类型,固定长度字符串类型与可变长度字符串类型在查询方面具有较大优势,固定长度字符串类型做索引性能要比可变长度字符串类型来的高很多,具体是因为哈希值的特点,这个不深入讲了。
表结构设计
我着重说表结构的设计:
一、主键,每新建一张表都要有主键,主键就是一个标识字段,新建主键的时候通常会建立聚集索引,聚集索引能提高查询性能,另外主键的设置有利于让各种数据库框架认识哪些字段是作为标识字段使用的。
二、表关系,分为一对多关系,一对一关系和多对多关系:
1.一对多关系,一个对多个,例如一张订单里有多个产品,那么订单就是一个,产品就是多个,订单对产品就是一对多。
2.一对一关系,单个对单个,例如一张病床上只能有一个病人,这就是一对一关系,不过一对一关系更多的是用于做表扩展字段的,例如我有一个张用户表User(Id,Name,PassWord,Phone,Address,CreateTime,State...),现在我要添加微信用户,我就可以新建一张表WeiXinUser(OpenId,WeiXinUserName,UserId...),将UserId作为外键,这样的好处是能重用,提高了扩展性,如果要对接支付宝,也可以仿照这种模式,这种也类似与类里面的继承关系。当然你也可以在User表里直接加上这些字段,但这样一来就会出现数据冗余,如果用户,特别是不用微信,支付宝的那些用户(例如PC用户)只限于几百个,几千个,那问题不大,属于合理数据冗余范围,但如果用户数量是几万个,几十万个,甚至几百万个,数据冗余量就非常大了,会非常影响数据库性能。
3.多对多关系,多个对多个,例如权限和用户组,多个权限可以用在多个用户组,用户组里面可以包含多个权限,就是多对多,如权限表UserRole,主键Id,用户组表UserGroup,主键Id,要做多对多关系,就新建一张表UserRole_UserGroup_Mapping,里面只有两个字段,UserRoleId作为外键对应UserRole的主键Id,UserGroupId作为外键对应UserGroup的主键Id。
三、无法确定字段的处理,我们通常会遇到这种问题,我要记录每个产品的产品参数,但我们无法确定产品参数有哪些,那么这个时候我们先确定一些产品最基本的参数,如Name.ProductPictures,CreateTime等等,要记着一点,就是如果产品的参数存在查询需求的,最好列为基本参数;确定完基本参数后,再加两个字段,Type,ProductData。Type将用来确定ProductData存储结构,而ProductData是用来存储序列化数据的,比如我可以将产品参数数据封装入对象,接着用Json序列化存入ProductData字段中,那取的时候我可以根据Type字段的值,反序列化,将ProductData里的Json数据封装入对象,再使用。所以这样产品表的设计是Product(Id,Name.ProductPictures,CreateTime,Type,ProductData)。
数据冗余
通常人认为数据冗余是不能存在的,会影响数据库性能,但其实如果对数据库性能影响不大,或者性能要求不高,它是可以存在的。比如权限,最常见的就是CMS权限,CMS权限有分为模型权限和栏目权限,模型权限是以模型的增、删、改为一个单元的,栏目权限是以栏目是否能访问为一个单元的,这两个是权限里面内容字段是都需要被查询的,那么我们会直接把模型权限和栏目权限放在一张表里,模型权限和栏目权限里面内容字段都是可空的,通过一个Type字段值去区分它。这个时候模型权限和栏目权限字段肯定有很多为空的,但因为权限的数据量本身不会很大,这些冗余量对数据库性能影响微乎其微,所以这样的数据冗余是合理的数据冗余。换言之,如果你不这么做,采用继承结构,那么在代码里,你不仅要多两个模型与之对应,还要做维护这两个表的一系列操作,大大的增加了工作量。