1.数据库设计简述
前言:什么是数据库设计?
简单来说,数据库设计就是根据业务系统的具体需要,结合我们所选用的DBMS(数据库管理系统),为这个业务系统构造出最优的数据存储模型。并建立好数据库中的表架构及表与表之间的关联关系的过程。使之能有效的对应用系统中的数据进行存储,并可以高效的对已经存储的数据进行访问。
1-2 为什么要进行数据库设计?
1-2-1 需求分析:
a.了解系统中所要的存储的数据
b.了解数据的存储特点(比如说,某些数据具有时效性,我们可以设置过期,归档等)
c.了解数据的生命周期(比如说,某些数据属于非核心数据,且数据量大,增长快等,比方说日志文件数据)
要搞清的一些问题:
1.实体所包含的属性有什么
2. 实体及实体之间的关系(1对1,1对多,多对多)
3.哪些属性或属性的组合可以唯一标识一个实体
4.存储特点:比如拿一个简单的电商系统来说:
用户模块,会随着系统上线,不断增长,永久存储
商品模块,对于下线商品可以归档存储,或数据迁移到下线商品表(用于以前的商品订单查询,不可删除)
订单模块,永久存储(分表、分库存储)
购物车模块,不用永久存储(可以设置归档、清理规则)
供应商模块,永久存储
1-2-2 逻辑设计:
使用ER图对数据库进行逻辑建模,与选用的具体的DBMS系统无关。
名词解释:
关系:一个关系对应常说的一张表
元组:表中的一行即为一个元组(一个实例)
属性:表中的一列即为一个属性(字段)
候选码:表中的某个属性组,它可以唯一确定一个元组(唯一索引)
主码:一个关系有多个候选码,选定其中一个为主码(主键)
域:属性的取值范围
分量:分组中的一个属性值(值)
ER图例说明:
矩形:表示实体集,矩形内写实体集名字
菱形:表示联系集
椭圆:表示实体的属性
线段:将属性连接到实体集,或将实体集连接到联系集
示例图:
1-2-3 物理设计:
根据数据库自身的特点,把逻辑设计转换为物理设计
1-2-4 维护优化:
a.新的需求进行建表
b.索引优化
c.大表拆分
2.数据库设计范式
2-1 数据库操作异常与数据冗余:
数据操作异常:
a.插入异常:如果其实体随着另一个实体的存在而存在,即缺少某个个体时无法显示这个实体,那么这个表就存在插入异常。
b.更新异常:如果更改表所对应的某个实体实例的单独属性时,需要将多行更新,那么这个表就存在更新异常。
c.删除异常:如果删除表的某一行来反映某实例实效时,导致另一个不同实体实例信息丢失个i,那么这个表就存在删除异常。
数据冗余:
是指相同数据在多个地方存在,或者说表中的某个列可以由其他列计算得到,就说表中存在数据冗余。
2-2数据库设计范式
2-2-1 第一范式
1NF的定义为:数据库表中的所有字段都是单一属性,不可再分的。(数据库中的表都是二维表)
2-2-2 第二范式
2NF的定义为:数据库的表中不存在非关键字段对任一候选关键字段的部分函数依赖。
部分函数依赖是指存在着组合关键字的某一关键字决定非关键字的情况。
换一句来说 //单关键字段的表都符合第二范式。
例子,如下表:
在这里使用商品名称
和供应商名称
标识出一件商品
上表存在以下的部分函数依赖关系:
商品名称
->价格、描述、重量、商品有效期
供应商名称
->供应商电话
所以对上表进行拆分:
2-2-3 第三范式
3NF的定义为:第三范式(3NF),就是不能重复存储相同的信息。在 2NF 的基础上,非主属性之间没有相互依赖(消除传递依赖)
例如,如下表:
存在以下传递函数依赖关系: 商品名称
->分类
->分类描述
修改为:
2-2-4 BCNF范式
在第三范式的基础上,数据库表中如果不存在任何任何字段对任一候选关键字段的传递函数依赖则符合BC范式。
也就是说如果是复合关键字,则复合关键字也不能存在函数依赖关系。
换句话来说,BC范式(BCNF)复合关键字之间也不能存在函数依赖关系
如下表:
假定:供应商联系人只能受雇于一家供应商,每家供应商可以供应多个商品,则存在如下决定关系:
(供应商,商品id)->(供应商联系人,商品数量)
(供应商联系人,商品id)->(供应商,商品数量)
所以有两种组合关键字的选择
存在以下关系不符合BCNF要求:
(供应商)->(供应商联系人)
(供应商联系人)->(供应商)
并且存在数据操作异常和数据冗余
所以要拆表:
3.数据库物理设计
思路概述:
a.选择合适的数据库管理系统,Mysql 、Oracle、Sql Server、Pgmysql
b.建立数据库、表以及命名规范。
c.根据所选的DBMS,选择合适的字段类型。
d.反范式化设计,冗余,以空间换时间。
Tips:a.Oracle按核数收费,适合大的事务支持(事务开销比较低)。--->电信、金融行业优选
b.SQLServer只支持Windows下平台开发,配合.net开发很适用。 --->中、小级企业
3-1 本例使用MySQL作为讲解
MySQL常用的存储引擎:
3-2 数据库及表字段的命名原则
数据库以及遵循可读原则、表意原则、长名原则。
1.可读性原则
使用大写和小写来格式化库对象名字以获取良好的可读性
例如:使用CustAddress而不是custaddress来提高可读性(这里要注意的是有些DBMS系统对表名的大小写是敏感的)
2.表意性原则,对象的名字应该能够描述它所标识的对象
3.长名原则,尽可能少使用或者不使用缩写,适用于数据库名之外的任一对象。
3-3 选择合适的字段类型
例如,对于birthday
这个字段可以有如下的选择:
列的数据类型一方面影响数据存储空间的开销,另一方面也会影响数据查询性能。
当一个列可以选择多种数据类型时,应该优先考虑数字类型,其次是时间或二进制类型,最后是字符类型。对于相同级别的数据类型,应该优先选择占用空间小的数据类型。
MySQL的时间戳格式只能存储到2037
年。
以上选择原则主要从下面两个角度考虑:
1.在对数据进行比较(查询条件、join条件及排序)操作时,同样的数据,字符处理往往比数字处理慢。
2.在数据库中,数据处理以页为单位,列的长度越小,利用性能越高。
char与archer如何选择?
1.如果列中要存储的数据长度差不多是一致的(例如电话或身份证号码),应该考虑用char
,否则应该考虑用varchar
2.如果列中的数据最大长度小于50byte,则一般也考虑使用char
(当然,如果这个列很少用,则基于节省空间和减少I/O的考虑,还可以使用varchar
)
3.一般不宜定于大于50byte的char
类型列
decimal与float如何选择?
1.decimal用于存储精确数据,而float只能由于存储非精确数据,故精确数据只能选择用decimal类型
2.由于float的存储空间开销一般比decimal下(精确到7位小数只需啊4个字节,而精确到15位小数只需要8字节),故非精确数据优先选择float类型
时间类型如何存储?
1.使用int来存储时间字段的优缺点
优点:字段长度比DateTime小
缺点:使用不方便,要进行函数转换
限制:只能存储到2038-1-19 11:14:07 即 2^32
总结:要经常去数据库读取时间数据时(如查看订单系统的时间),最好还是用DateTime类型存储;
如果只是存日期,很少去读写时间值,可用时间戳格式存
2.需要考虑存储的时间粒度
如存储是年还是月等
其它注意事项:
如何选择主键?
1.区分业务主键和数据库主键
业务主键用于标识业务数据,进行表与表之间的关联
数据库主键为了优化数据存储(Innodb会生成6个字节的隐含主键)
2.根据数据库的类型,考虑主键是否要顺序增长
有些数据库是按主键的顺序逻辑存储的
3.主键的字段类型所占空间要尽可能的小
对于使用聚集索引方式存储的表,每个索引后都会附加主键信息
避免使用外键约束 :
· 1.降低数据导入的效率
2.增加维护成本
3.虽然不建议使用外键约束,但是相关联的列上一定要建立索引
避免使用触发器 :
1.降低数据导入的效率
2.可能会出现意想不到的数据异常
3.使业务逻辑变的复杂
关于预留字段 :
1.无法准确的知道预留字段的类型
2.无法准确知道预留字段中所存储的内容
3.后期维护预留字段所要的成本,同增加一个字段所需要的成本是相同的
4.严禁使用预留字段
3-3.反范式化设计
反范式化是针对范式化而言的,在前面介绍了数据库设计的第三范式,所谓的反范式化就是为了性能和读取效率的考虑而适当的对第三范式的要求进行违反,而允许存在少量的数据冗余
换句话说反范式化就是使用空间来换取时间。
反范式化的优点及注意点:
a.减少表的关联数量
b.增加数据的读取效率(互联网数据的读写比例一般大概在3:1或者4:1之间)
c.反范式化一定要适度