首先对数据库的整体结构进行图形化的设计,然后在依据图形对数据库结构进行建立。简单来说,数据库设计就是根据业务系统的具体需要,结合我们所选用的DBMS(数据库管理系统),为这个业务系统构造出最优的数据存储模型,并建立好数据库中的表结构及表与表之间的关联关系的过程。使之能有效的对应用系统中的数据进行存储,并可以高效的对已经存储的数据进行访问。
应用系统中的数据可以有多种存储方式,可以把所有数据存储在一张表中,但是这样就不能达到高效访问的目的。
阿里云代金券2000元免费领取地址:https://promotion.aliyun.com/ntms/yunparter/invite.html
新老阿里云账户均可领取!可用于购买阿里云服务器ECS、云数据库RDS、虚拟主机、安骑士、DDoS高防IP等100多云计算产品。 代金券自领取之日起,有效期是30天,请及时使用,过30天后还可以重新领取。
为什么要进行数据库设计?
好的设计:减少数据多余,避免数据维护异常,节约存储空间,高效的访问
坏的设计:存在大量数据多余,存在数据插入、更新、删除异常,浪费大量存储空间,访问数据低效。
如果数据库已经在生产环境运行了一段时间之后,在想对数据库进行调整,就会影响业务的正常运行,所以在最初就要设计出简洁、高效的数据结构。
设计步骤:
1.需求分析:数据是什么,数据有哪些属性,数据和属性各自的特点有哪些;
2.使用ER图对数据库进行逻辑建模(跟我们所选的具体的数据库管理系统是没有关系的),大部分的表关系也是在这一步完成的
3.物理设计:根据数据库自身的的特点把逻辑设计转换为物理设计;
4.维护优化:新的需求进行建表,索引优化,大表拆分。随着应用程序上线的时间越来越久,需求越来越多,数据结构也会越来越复杂,所以在维护优化的时候也要遵循以上几步,完了之后再进行页面的操作,这样保证数据结构永远是最优的。
需求分析:
了解系统中所要存储的数据
了解数据的存储特点,比如有的有时效性,可以采用过期清理的方式存储,有的没有
了解数据的生命周期,可以采用分库分表的方式存储
小问题:
实体及实体之间的关系(1对1,1对多,多对多),可能是一个实体对应一个表,也可能是多个实体对应一个表
实体所包含的属性有什么
哪些属性或属性的组合可以唯一标识一个实体
逻辑设计:
1将需求转化为数据库的逻辑模型
2通过ER图的形式对逻辑模型进行展示
3同所选用的具体的DBMS无关
常见数据库设计范式:
第一范式、第二范式、第三范式及BC范式,当然还有第四及第五范式,不过重点还是前三个范式上,这也是目前我们大多数数据库设计所要遵循的范式。
第一范式
数据库表中的所有字段都是单一属性,不可再分的。这个单一属性是由基本的数据类型所构成的,如整数、浮点型、字符串等,第一范式要求数据库中的表都是二维表。
第二范式
数据库的表中不存在非关键字段对任一候选关键字段的部分函数依赖。部分函数依赖是指存在着组合关键字中的某一关键字决定非关键字的情况。所有单关键字段的表都复合第二范式。
第三范式
第三范式是在第二范式的基础之上定义的,如果数据表中不存在非关键字段,对任意候选关键字段的传递函数依赖则符合第三范式
数据操作异常:
1插入异常,如果某实体随着另一个实体的存在而存在,即缺少某个实体时无法表示这个实体,那么这个表就存在插入异常。
2.更新异常,如果更改表所对应的某个实体实例的单独属性时,需要将多行更新,那么这个表存在更新异常。
3.删除异常,如果删除表的某一行来反映某实体实例失效时导致另一个不同实体实例信息丢失,那这个表存在删除异常。
4数据多余,相同的数据在多个地方存在,或者表中的某个列可以由其他列计算得到,这样就是表中存在数据多余。
物理设计:
常见的的DBMS系统
Oracle/SQLServer:商业数据库,要考虑版权问题,即成本问题
MySQL/PgSQL:开源数据库,不需支付版权费用
功能上
Oracle:口碑好,性能高,适合大的事务操作,事务成本低,其他三个事务成本高,适合小的事务
操作系统上
SQLServer:微软的数据库产品,目前只支持在Windows上运行,其他三个可以在Windows或Linux
开发语言
.net语言,用SQLServer,其他语言用其他三个
适合场景
MySQL、PgSQL:适用于互联网项目
Oracle、SQLSer:更适合企业级项目,电信、ERP系统
MYSQL:由于它是开源数据库,只要符合他的存储协议,任何厂商都可以实现自己的存储引擎,比较常用的几种:MyISAM/MRG_MYISAM/Innodb/Archive/Ndb cluster,其中使用最多的是Innodb(支持事务,支持MVCC的行级锁,主要应用场景是事务处理),在维护上相比较其他的也好一些。
字段类型的选择原则:列的数据类型一方面影响数据存储空间的开销,另一方面也会影响数据查询性能。当一个列可以选择多种数据类型时,应该优先考虑数字类型,其次是日期或二进制类型,最后是字符类型。对于相同级别的数据类型,应该优先选用占用空间小的数据类型。
以上选择原则主要从两个角度考虑:
- 在对数据库进行比较(查询条件、JOIN条件及排序)操作时,同样的数据,字符处理往往比数字处理慢。
2.在数据库中,数据处理以页为单位,列的长度越小,利于性能提升。如,SQLServer是8K字节一页,MYSQL在Innodb中默认16K字节一页,列的长度越小,一页所能存储的数据量就越多,在加载相同数据量的时候,如果列越小,页数越少,IO的性能就会提高,数据库最大的瓶颈不是CPU,而是磁盘的IO瓶颈。
- 如果列中要存储的数据长度差不多是一致的,则应该考虑用char,否则应考虑用Varchar
- 如果列中的最大数据长度小于50Byte,则一般也考虑用Char,当然,如果这个列很少用,则基于节省空间和减少IO的考虑,还是可以用Varchar
- 一般不宜定义大于50Byte的Char类型列
不同的字符类型它的字节长度是不一样的,如UTF-8,每个字符占3个字节。
- decimal用于存储精确数据,而Float只能用于存储非精确数据。
- 由于Float的存储空间开销一般比Decimal小(精确到7位小数只需要4个字节,而精确到15位小数只需要8字节)。因此,精确数据只能选择Decimal类型,而非精确数据优先选择Float类型。
时间类型
- 使用Int存储时间字段的优缺点
优点:字段长度比datetime小
缺点:使用不方便,要进行函数转换
限制:只能存储到2038-1-19 11:14:07即2^32为2147483648
- 需要存储的时间粒度
年月日时分秒周
- 区分业务主键和数据库主键
a) 业务主键用于表示业务数据,进行表与表之间的关联
b) 数据库主键为了优化数据存储(Innodb会生成6个字节的隐含主键)
- 根据数据库的类型,考虑主键是否要顺序增长
有些数据库是按主键的顺序逻辑存储的
- 主键的字段类型所占空间要尽可能的小
对于使用聚集索引方式存储的表,每个索引后都会附加主键信息
避免使用外键约束
外键是用于保持数据完整性的一种方式,但是在高并发的互联网中,如果我们使用外键,会带来负面影响,首先,对数据的导入操作,如果使用外键,每写一条数据都要查是否符合外键约束,是非常耗时的,尤其在高并发的时候。索引是为提高查询效率而建立的。1.降低数据导入的效率2增加维护成本3虽然不建议使用外键约束,但是相关联的列上一定要建立索引
避免使用触发器
我们经常会使用触发器来减少程序上的逻辑处理,比如在操作某张表的时候同时要记录日志,通常会使用触发器的方式向一张日志表中插入数据。对于MySQL来说,使用Innldb,虽然支持触发器,但是每一种触发器只支持一个,before/after……一共就需要6种触发器,如果建立触发器之后,在使用一些其他的工具,就会出现不能建立触发器的情况,给维护带来影响。如果大量使用触发器来保证业务逻辑,业务逻辑出现变更,其他人不知道的情况下,可能会影响业务规则。1.降低数据导入的效率2可能会出现意想不到的数据异常3使业务逻辑变得复杂。
关于预留字段
- 无法准确的知道预留字段的类型
- 无法准确地知道预留字段中所存储的内容
- 后期维护预留字段所要的成本,同增加一个字段所需要的成本是相同的
- 严禁使用预留字段
反范式化
反范式化是针对范式化而言的,是为了性能和读取效率的考虑而适当的对第三范式的要求进行违反,而允许存在少量的数据多余,即用空间来换时间。
好处:1减少表的关联数量
2.增加数据的读取效率
3.反范式化一定要适度
数据库维护和优化
维护数据字典
- 使用第三方工具对数据字典进行维护
- 利用数据库本身的备注字段来维护数据字典
3导出数据字典
维护索引
如何选择合适的列建立索引
1出现在Where从句,Group By从句,ORDer By从句中的列
2可选择性高的列要放到索引的前面
3索引中不要包括太长的数据类型
注意:索引并不是越多越好,过多的索引不但会降低写效率,而且会降低读的效率;定期维护索引碎片;在SQL语句 中不要使用强制索引关键字
维护表结构
1使用在线变更表结构的工具2同时对数据字典进行维护3控制表的宽度和大小
数据库中适合的操作
1批量操作VS逐条操作:批量适合在数据库中完成,逐条适合在程序中完成
2禁止使用Select*这样的查询:IO的浪费,程序可能会出错
3控制使用用户自定义函数:虽然函数很方便,但大量使用会对索引造成影响,使用函数,列中的索引就会不起作用
4不要使用数据库中的全文索引:需要另外建立索引文件对索引维护,对中文的支持不太好,如果需要,最好使用专业的搜索引擎完成
在适当的时候对表进行水平拆分和垂直拆分
为了控制表的宽度可以进行表的垂直拆分:当列非常多的的时候,每页的行数就会减少,存储的数据就少了,IO 的效率就会减小,这时可以把一张大表拆分成几张小表,拆分原则:1经常一起查询的列放在一起2text/blob等大字段拆分出到附加表中,可以优化IO,同时减少SQL的复杂程度,不需要关联操作了
表的水平拆分
为了控制表的大小可以进行表的水平拆分
每张表都有主键,可以利用主键的Hash值进行拆分