······数据库设计就是根据业务系统的具体需要,结合我们所选用的DBMS(数据库管理系统),为这个业务系统构造出最优的数据存储模型。并建立好数据库中的表结构及表与表之间的关联关系的过程。使之能有效的对应用系统中的数据进行存储,并可以高效的对已经存储的数据进行访问。
常见的关系型数据库:MySQL、Oracle、SQLServer、PgSQL
常见的NoSQL系统:Mongo、Redis、Memcache
进行数据库设计的好处:尽可能的减少数据冗余;避免数据维护异常;节约存储空间;保证数据高效访问;
数据库需求的作用点:数据是什么;数据都有哪些属性;数据和属性各自的特点有哪些;
数据库设计的步骤:
需求分析
逻辑设计:使用ER图对数据库结构进行逻辑建模
物理设计:根据数据库自身的特点把逻辑设计转换成物理设计
维护优化:新的需求进行建表;索引优化;大表拆分;
需求分析前提就是对整体系统的把控:了解系统中所要存储的数据;了解数据的存储特点;了解数据的生命周期;同时,在需求分析的时候,要搞清楚:实体及实体之间的关系(1对1,1对多,多对多);实体所包含的属性;哪个属性或者属性的组合可以唯一表示一个实体;分析这些实体的存储特点;
逻辑设计:就是将需求转化为数据库的逻辑模型,主要是通过ER图的形式对逻辑模型进行展示,这一步同所选择的具体的DBMS系统无关
名词解释
关系:一个关系对应通常所说的一张表
元组:表中的一行即为一个元组
属性:表中的一列即为一个属性,每一个属性都有一个属性名
候选码:表中的某个属性组,它可以唯一确定一个元组
主码:一个关系有多个候选码,选定其中一个为主码
域:属性的取值范围
分量:元组中的一个属性值
ER图图例说明:
矩形:表示实体集,矩形内写实体集的名字
菱形:表示联系集
椭圆:表示实体的属性
线段:将属性连接到实体集,或将实体集联系到联系集
如下图,便是一个小型电商的ER图设计示例
其中菱形的部分就是联系集,主要是为了把一些多对多的关系转换为一对多的关系,方便我们日后使用数据;
每个线段的两侧标记的数字字母,便表示了两个实体集之间的关系;
在其中一些实体的属性中,其中的一些属性带有下划线,表示为当前实体集所选用的主码,也就是一般来说对应数据库的主键;
关于范式这里就是提一下这些概念,不展开篇幅来理解这些范式了
常见主流的数据库设计范式包括:第一范式,第二范式,第三范式以及BC范式,当然还有第四,第五范式,这里只提这些主流为大多数数据库设计所遵循的范式;范式的主要作用就是为了使我们所使用的数据库能够更加的简洁高效,结构清晰;同时尽量减少在数据库插入,更新,删除时所可能产生的错误及异常,以及减少数据冗余
操作异常
插入异常:如果某实体随着另一个实体的存在而存在,即缺少某个实体时无法表示这个实体,那么这个表就存在插入异常;
更新异常:如果更改表所对应的某个实体实例的单独属性时,需要将多行更新,那么就说这个表存在更新异常;
删除异常:如果删除表的某一行来反映某实体实例失效时导致两一个不同实体实例信息丢失,那么这个表就存在删除异常;
数据冗余
数据冗余就是相同的数据在多个地方存在,或者是表中的某个列可以由其他列计算得到,这样的情况就是存在着数据的冗余;这样的情况下,会导致数据在做修改时产生不一致;过多的数据也会使得数据占用空间增大,操作变慢;
定义:数据库表中的所有字段都是单一属性,不可再分;即第一范式要求数据库中的表都是二维表
单一属性是由基本的数据类型所构成的,如证书、浮点数等等;
定义:数据库中表中不存在非关键字段对任一候选关键字段的部分函数依赖;即第二范式要求所有单关键字段的表都符合第二范式
部分函数依赖是指存在着组合关键字中的某一关键字决定非关键字的情况
定义:在第二范式的基础之上定义的,如果数据表中不存在非关键字段,对任意候选关键字段的传递函数依赖则符合第三范式
定义:在第三范式的基础之上,数据库表中如果不存在任何字段对任一候选关键字段的传递函数则符合BC范式;即如果表中为复合关键字,那么复合关键字之间也不能存在函数依赖关系
选择数据库,除了其本身的能够适配的业务之外,我们最长考虑的也就是使用时候所产生的成本问题;
开源数据库,只要我们在使用的时候符合社区协议,就不需要支付额外的版权费用;而商业数据库,面对大量的数据而选择高核心配置的时候,就要去考虑它商业版权这部分的费用,每年的费用不算低;
其余的方面,就要考虑比如操作系统呀,语言之间的适配性,以及开发的场景(开源数据库更适合互联网项目,而商业数据库更适合企业级项目)等等多个方面;
常用的存储引擎有
a. MyISAM:这个是MySQL5.5之前的存储引擎,它不支持事务,主要是用于SELECT和INSERT,不能进行频繁的读写操作;
b. MRG_MyISAM:这个相当于是多个MyISAM的合并;
c. Innodb:目前MySQL使用最多也是默认的一个存储引擎,可以满足基本上所有的事务处理需求;
d. Archive:仅支持INSERT,SELECT,多于用日志记录场景;
e. Ndb cluster:这个多用于MySQL集群,但是数据存储在内存中,当数据量很大的时候,使用起来就会受限;
所有对象的命名应该遵循下述原则:
字段类型的选择原则:列的数据类型一方面影响数据存储空间的开销,另一方面也会影响数据查询性能;当一个列可以选择多种数据类型的时候,应该优先考虑数字类型,其次是日期或者二进制类型,最后是字符类型;相对于同级别的数据类型,应该优先选择占用空间小的数据类型;
列类型 | 存储空间 |
---|---|
TINYINT | 1个字节 |
SMALLINT | 2个字节 |
MEDIUNINT | 3个字节 |
INT | 4个字节 |
BINGINT | 8个字节 |
DATE | 3个字节 |
DATETIME | 8个字节 |
TIMESTAMP | 4个字节 |
CHAR(M) | M个字节,1<=M<=255 |
VARCHAR(M) | L+1个字节,L<=M |
根据上表中的常见的各个字段的存储空间,我们一边按照下面两个角度来考虑:
a. 在对数据进行比较(查询条件、JOIN条件及排序)操作时,同样的数据,字符处理往往比数字处理慢
b. 在数据库中,数据处理以页为单位,列的长度越小,越有利于性能提升
char与varchar的选择
a. 如果列中要存储的数据长度差不多是一致的,比如电话,身份证号等等,则应该考虑用char,否则考虑用varchar;
b. 如果列中的最大数据长度小于50Byte,则一般也考虑用char(如果这个列很少用到,则基于节省空间和减少I/O的考虑,也可以选择用varchar)
c. 一般不宜定义大于50Byte的char类型列
decimal与float的选择
a. decimal用于存储精确数据,而float只能用于存储非精确数据;精确数据只能选择用deciaml类型
b. 由于float的存储空间开销一般比decimal小(精确到7位小数只需要4个字节,精确到15位小数只需要8个字节),所以非精确数据优先选择float类型
时间类型的选择
a. 使用int来存储时间字段:其字段长度比datetime小,但是需要进行函数转换,使用上带来不方便,且受限只能存储到2的32次幂,即2147483648,转化完就是2038-01-19这里,所以一般适合只存储少查询的数据;
b. 需要存储的时间粒度:年 月 日 时 分 秒,这里面就是year这类存储类型;
如何选择主键
a. 区分业务主键和数据库主键:业务主键用于标识业务数据,进行表与表之间的关联;数据库主键为了优化数据存储(Innodb会生成6个字节的隐含主键);
b. 根据数据库类型,考虑主键是否要顺序增长;
c. 主键的字段类型所占的空间要尽可能的小(对于使用聚集索引方式存储的表,每个索引后都会附加主键信息);
避免使用外键约束
a. 降低数据导入的效率;
b. 增加维护成本;
c. 虽然不建议使用外键约束,但是相关联的列上一定要建立索引;
避免使用触发器
a. 降低数据导入效率;
b. 可能会出现意想不到的数据异常;
c. 使业务逻辑变得复杂;
预留字段(本意是增加程序的可扩展性)
a. 无法准确的知道预留字段的类型;
b. 无法准确的知道预留字段中所存储的内容;
c. 后期维护预留字段所要的成本,同增加一个字段所要的成本基本相同
d. 严禁使用预留字段
反范式化设计
反范式化是针对范式化而言,也就是常见的四个范式。反范式就是为了性能和读取效率的考虑而适当的对第三范式的要求进行违反,而允许存在少量的数据冗余,就是使用空间来换取时间
a. 减少了表的关联数量;
b. 增加了数据的读取效率;
c. 反范式化一定要适度;
数据字典是指对数据的数据项、数据结构、数据流、数据存储、处理逻辑、外部实体等进行定义和描述,其目的是对数据流程图中的各个元素做出详细的说明,使用数据字典为简单的建模项目
a. 使用第三方工具对数据字典进行维护;
b. 利用数据库本身的备注字段来维护数据字典,例如MySQL的COMMENT;
选择合适的列来建立索引
a. 出现在WHERE从句,GROUP BY从句,ORDER BY从句中的列;
b. 可选择性高的列要放在索引的前面;
c. 索引中不要包括太长的数据类型;
注意事项
a.索引并不是越多越好,过多的索引会降低读写的效率;
b.定期维护索引碎片;
c.在SQL语句中不要使用强制索引关键字;
a.使用在线变更表结构的工具,MySQL5.6版本之后自身便支持了此项;
b.同时对数据字典进行维护;
c.控制表的宽度和大小;
a.批量操作 VS 逐条操作;
b.禁止使用SELECT *这样的查询
c.控制使用用户自定义函数;
d.不要使用数据库中的全文索引;
表的垂直拆分:为了控制表的宽度而进行的垂直拆分;
a.将经常在一起查询的列放在一起;
b.将text,blob等大字段拆分出到附加表中;
表的水平拆分:为了控制表的大小而进行的水平拆分;
利用Hash Key来进行水平拆分;