目录
- 一、数据库设计的重要性
- 二、范式 - 简介:
- 1、什么是范式?
- 第一范式 - 单一列
- 第二范式 - 中间表 - 一对多
- 第三范式 - 不产生中间表 - 一对一、多对一
- 三、数据库表设计的注意要点
- 参考链接
一、数据库设计的重要性
良好的表结构设计是高性能的基石,应该根据系统将要执行的业务查询来设计,这往往需要权衡各种因素。糟糕的表结构设计,会浪费大量的开发时间,严重延误项目开发周期,让人痛苦万分,而且直接影响到数据库的性能,并需要花费大量不必要的优化时间,效果往往还不怎么样。
在数据库表设计上有个很重要的设计准则,称为范式设计。
二、范式 - 简介:
1、什么是范式?
范式来自英文Normal Form
,简称NF
。MySQL是关系型数据库,但是要想设计—个好的关系,必须使关系满足一定的约束条件,此约束已经形成了规范,分成几个等级,一级比一级要求得严格。满足这些规范的数据库是简洁的、结构明晰的,同时,不会发生插入(insert)、删除(delete)和更新(update)操作异常。反之则是乱七八糟,不仅给数据库的编程人员制造麻烦,而且面目可憎,可能存储了大量不需要的冗余信息。
目前关系数据库设计有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般来说,数据库只需满足第三范式(3NF)就行了(也就是前三个范式,因为后面的范式是在前面的范式演变过来的,后面的范式包括前面的范式)。
第一范式 - 单一列
定义: 属于第一范式关系的所有属性都不可再分,即数据项不可分。
理解: 第一范式强调数据表的原子性,是其他范式的基础。
将数据库表分为一个单一独立的属性列,比如姓名、年龄、性别、联系电话等等,这便是第一范式,数据库表的原子性。
上表就符合第一范式关系。但日常生活中仅用第一范式来规范表格是远远不够的,依然会存在数据冗余过大、删除异常、插入异常、修改异常的问题,此时就需要引入规范化概念,将其转化为更标准化的表格,减少数据依赖。
实际上,1NF是所有关系型数据库的最基本要求,你在关系型数据库管理系统(RDBMS),例如SQL Server,Oracle,MySQL中创建数据表的时候,如果数据表的设计不符合这个最基本的要求,那么操作一定是不能成功的。也就是说,只要在RDBMS中已经存在的数据表,一定是符合1NF的。
第二范式 - 中间表 - 一对多
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。
第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。通常在实现来说,需要为表加上一个列,以存储各个实例的惟一标识。例如员工信息表中加上了员工编号(emp_id)列,因为每个员工的员工编号是惟一的,因此每个员工可以被惟一区分。这个惟一属性列被称为主关键字或主键、主码。
也就是说要求表中只具有一个业务主键,而且第二范式(2NF)要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。什么意思呢?
这句话的意思是一张业务表,要和另外的一张业务表有所联系,那么最最应该设计的是中间表,中间表存储了两张业务表的业务关键字。
要特别特别注意:这里的业务关键字可不是指 id 主键,比如员工表里面的员工编号,或者部门表里面的部门编号,这些都是业务关键字段。
这个中间表具体的作用是一个信息包含了多个附属信息,就可以采用第二范式中间表来存储数据,比如一个产品会有多个订单,或者一个订单里面有多个产品等等。
————
| 中间表 |
————
| 1 号产品 id | 1 号订单id |
| 1 号产品 id | 2 号订单id |
————————————
| 1 号订单 id | 1 号产品id |
| 1 号订单 id | 2 号产品id |
第三范式 - 不产生中间表 - 一对一、多对一
指每一个非主属性既不部分依赖于也不传递依赖于业务主键,也就是在第二范式的基础上消除了非主键对主键的传递依赖。例如,存在一个部门信息表,其中每个部门有部门编号(dept_id)、部门名称、部门简介等信息。那么在员工信息表中列出部门编号后就不能再将部门名称、部门简介等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。
具体的设计:
通常遇到一些数据项,会包含了其他数据库表的 id 编号等等,详细的情况是,一对多,但是本身却是多对一,怎么理解这个意思?
这里的 一对一,指的是,该数据只有一个数据项对应一个数据项,但是另外的一个数据项却能对应多个数据项,比如员工只属于一个部门,而一个部门却可以有几百个员工对应。
借用一下图来解释更清楚,下面这张图中,第一张订单表是错误的,产品名称不能接着写进去订单表里面,需要创建一个产品表来存储,不然在订单表里面继续添加产品名称列,那不正是数据冗余吗?多次一举。
把订单表里的产品名称删除了,只剩下产品 id 就满足第三范式。
三、数据库表设计的注意要点
- 库名与应用名称保持一致
- 表名,字段名必须使用小写字母或数字,且开头不能使用数字
- 表名不能使用复数
- 表命名规范,业务名称_表的作用
- 表必备三个字段,id,create_time,update_time,其中id为主键类型为 bigint unsigned、单表时自增、步长为 1,(如果使用分库分表集群部署,则id类型为verchar,非自增,业务中使用分布式id生成器)
create_time,update_time 为datetime 类型,前者现在时表示主动创建,后者过去分词表示被动更新 - 单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
- 表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (1 表示是,0 表示否)。
说明:任何字段如果为非负数,必须是 unsigned。
正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。 - 小数类型为 decimal,禁止使用 float 和 double。 说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不 正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。
- 如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
- varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。
- 唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。
说明:uk_ 即 unique key;idx_ 即 index 的简称 - 不得使用外键与级联,一切外键概念必须在应用层解决。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。