1.为什么要进行数据库设计?
优良的设计 | 糟糕的设计 |
---|---|
减少数据冗余 | 存在大量的数据冗余 |
避免数据维护异常 | 存在数据插入,更新,删除异常 |
节约存储空间 | 浪费大量量存储空间 |
高效的访问 | 访问数据低效 |
2.数据库设计流程
需求分析-->逻辑设计-->物理设计-->维护优化
2.1需求分析阶段任务:
- 数据是什么
- 数据有哪些属性
- 数据和属性各自的特点有哪些
2.1.1 需求分析阶段需要弄清楚的问题
实体与实体间的关系(1对1,1对多,多对多)
实体所包含的属性有什么?
哪些属性或属性的组合可以唯一表示一个实体(主键)
2.2逻辑设计阶段任务:
- 画E-R图进行逻辑建模
2.3物理设计阶段任务:
- 根基数据库自身的特点将逻辑设计转换为物理设计
2.3.1物理设计要做什么
选择合适的数据库管理系统
定义数据库、表及字段的命名规范
根据所选DBMS系统选择合适的字段类型
4.反范式化设计
2.4维护优化阶段任务:
- 新的需求进行建表
- 索引优化
- 大表拆分
2.5 MySQL常用的存储引擎
存储引擎 | 事务 | 锁粒度 | 主要应用 | 忌用 |
---|---|---|---|---|
MyISAM | 不支持 | 支持并发插入的表级锁 | SELECT,INSERT | 读写操作频繁 |
MRG_MYISAM | 不支持 | 支持并发插入的表级锁 | 分段归档,数据仓库 | 全局查找过多的场景 |
Innodb | 支持 | 支持MVCC的行级锁 | 事务处理 | 无 |
Archive | 不支持 | 行级锁 | 日志记录,只支持insert,select | 需要随机读取,更新,删除 |
Ndb cluster | 支持 | 行级锁 | 高可用性(应用MySQL集群) | 大部分应用 |
2.6 表及字段的命名规则
所有对象命名应遵循下述原则
- 可读性原则
使用大写和小写来格式化的库对象名字以获得良好的可读性.。例如使用CustAddress而不是custaddress来提高可读性(这里要注意有些DBMS系统对表名的大小写是敏感的).
- 表意性原则
对象的名字应该能够描述他所标识的对象。例如:对于表、表的名称应该能够体现表中存储的数据内容;对于存储过程,存储过程名称应该能够体现存储过程的功能。
- 长名原则
尽可能少使用或者不使用缩写,适用于数据库名之外的任一对象。
2.7 字段类型的选择
例如:birthday字段可以选择的字段类型有:
- char(10): '1978-03-01'
- varchar(20): '1978-03-01'
- Datetime: 1978-03-01
- int: 257529600
2.7.1 字段类型选择原则(重点)
列的数据类型一方面影响数据存储空间的开销,另一方面也会影响数据查询性能。当一个列可以选择多种数据类型时,应该优先选择数字类型,其次时日期或二进制类型,最后是字符类型。对于相同级别的数据类型,应该优先选择占用空间小的数据类型。
列类型 | 存储空间 |
---|---|
TINYINT | 1字节 |
SMALLINT | 2字节 |
MEDIUMINT | 3字节 |
INT | 4字节 |
BIGINT | 8字节 |
DATE | 3字节 |
DATETIME | 8字节 |
TIMESTAMP | 4字节(只能存储到2037年) |
CHAR(M) | M字节,1<=M<=255 |
VARCHAR(M) | L+1字节,在此L<=M和1<=M<=255 |
以上原则主要从下面两个角度考虑
- 对于数据进行比较(查询条件、JOIN条件及排序)操作时,同样的数据、字符处理往往比数字处理慢。
- 数据库中,数据处理以页为单位,列的长度越小,利于性能提升。
2.7.2 char与varchar如何选择
如果列中要存储的数据长度差不多一致的(身份证号、电话等),则应该考虑用char;否则应该考虑用varchar。
如果列中的最大数据长度小于50Byte,则一般也考虑用char。(当然,如果这个列很少用,基于节省空间和减少I/O的考虑,还是可以选择用varchar)。
一般不宜定义大于50Byte的char类型列。
2.7.3 decimal 与float如何选择
- decimal(涉及金额类的数据)用于存储精确数据,而float只能用于存储非精确数据。
- 由于float的存储空间开销一般比decimal小(精确到7位小数只需要4字节,而精确到15位小数只需要8字节),故非精确数据优先选择float类型。
2.7.4 时间类型如何存储
-
使用int来存储时间字段大的优缺点
优点: 字段长度比datetime小。
缺点: 使用不方便,要进行函数转换。
限制: 只能存储到2038-1-19 11:14:07即2^32
-
需要存储的时间粒度
年 月 日 小时 分 秒 周
2.7.5 如何选择主键
-
区分业务主键和数据库主键
业务主键用于标识业务数据,进行表与表之间的关联
数据库主键为了优化数据存储(Innodb会生成6个字节隐含主键)
-
根据数据库的类型,考虑主键是否要顺序增长
有些数据库是按主键的顺序逻辑存储的
-
主键二点字段类型所占空间要尽可能的小
对于使用聚集索引方式存储的表,每个索引后都会附加主键信息。
2.7.6 避免使用外键约束(重点)
- 降低数据导入的效率
- 增加维护成本
- 虽然不建议使用外键约束,但相关联的列上一定要建立索引
2.7.7 避免使用触发器
- 降低数据导入的效率
- 可能出现意想不到的数据异常(比如:程序逻辑变更,但新来的程序员不知道用到了触发器,而触发器依然做着原来的工作,这可能会对业务逻辑产生影响)
- 使业务逻辑变复杂
2.7.8 关于预留字段
- 无法准确的知道预留字段的类型
- 无法准确的知道预留字段中存储的内容
- 后期维护预留字段所要的成本,同增加一个字段所需要的成本是相同的
- 严禁使用预留字段
2.7.9 什么是反范式化
反范式化是针对范式化而言的,在前面介绍了第三范式,所谓的反范式化就是为了性能和读取效率的考虑而适当的对第三范式要求进行违反,而允许存在少量的数据冗余,换句话说反范式化就是使用空间来换取时间。
2.7.10 为什么反范式化
- 减少表的关联数量
- 增加数据的读取效率
- 反范式化一定要适度
2.8数据维护和优化要做什么
- 维护数据字典
- 维护索引
- 维护表结构
- 在适当的时候对表进行水平拆分或垂直拆分
2.8.1 如何维护数据字典
- 使用第三方工具对数据字典进行维护
- 利用数据库本身的备注字段来维护数据字典。以MySQL为例。
CREATE TABLE customer(
cust_id INT AUTO_INCREMENT NOT NULL COMMENT '自增ID',
cust_name VARCHAR(10) NOT NULL COMMENT('客户姓名'),
PRIMARY KEY(cust_id)
)COMMENT '客户表'
2.8.2 如何维护索引
如何选择合适的列建立索引?
- 出现在WHERE从句,GROUP BY 从句, ORDER BY从句的列
- 可选择性高的列要放在索引的前面
- 索引中不要包括太长的数据类型
注意事项
- 索引并不是越多越好,过多的索引不但会降低写效率而且会降低读效率
- 定期维护索引碎片
- 在SQL语句中不要使用强制索引关键字
2.8.3 如何维护表结构
注意事项
- 使用在线变更表结构的工具。MySQL5.5之前可以使用pt-online-schema-change,MySQL5.6之后本身支持在线表结构的变更
- 同时对数据字典进行维护
- 控制表的宽度和大小
2.8.4 数据库中合适的操作
- 批量操作VS逐条操作
- 禁止使用Select * 这样查询
- 控制使用用户自定义函数
- 不要使用数据库中的全文索引
2.8.5 表的垂直拆分
为控制表的宽度可以进行表的垂直拆分,拆分表的原则:
- 经常一起查询的列放在一起
- text,blob等大字段拆分出到附加表中
2.8.6 表的水平拆分
水平拆分原则(表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放)
- 通常情况下,我们使用取模的方式来进行表的拆分;比如一张有400W的用户表users,为提高其查询效率我们把其分成4张表users1,users2,users3,users4通过用ID取模的方法把数据分散到四张表内Id%4+1 = [1,2,3,4]然后查询,更新,删除也是通过取模的方法来查询
注意: 进行水平拆分后的表,字段的列和类型和原表应该是相同的,但是要记得去掉auto_increment自增长
参考视频链接:数据库那些事