定义
所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。简而言之,第一范式就是无重复的列。
上面这张表就不符合第一范式,有重复的列,应该将 name-age 拆分成 name 和 age 两个列
定义
第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一地区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键、主码。
上面这张订单表,我们看到订单 id 为 1 的订单包含了两个产品,没有一个唯一的列被称为关键字,所以需要加上一个关键字主键
这张表需要优化成
订单表主表:
订单表明细
这样订单明细表中就依赖关键字 id,id 是唯一的主键,符合第二范式
满足第三范式(3NF)必须先满足第二范式(2NF)。第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。
上面这个订单表的设计,它依赖的商品信息过多,应该将商品信息拆分出来一张表单独存放
商品表中存储商品相关信息,订单表中只存放商品 id,不存储名称等信息
总结
在日常工作中,我们在数据库设计方面基本上满足以上三个范式就可以了,至于BCNF范式
,第四范式(4NF)
作为了解即可
设计表时类型选择应该遵循以下几个规则
1、更小的字段,CPU 处理周期更少
2、简单就好
3、尽量避免 NULL
类型 | 字节数 | 说明 |
---|---|---|
tinyint | 1 字节 | 对应 Java 中的 boolean 类型 |
smallint | 2 字节 | |
mediumint | 3 字节 | |
int | 4 字节 | |
bigint | 8 字节 | 对应 Java 中的 Long 类型 |
无符号
在数据库管理工具中我们进程见到无符号这个选项
勾选了无符号,说明这个字段只能存储正数,有符号则存储范围是负数~正数
MySQL 实数有三种类型,float
、double
、decimal
类型 | 说明 | 字节数 |
---|---|---|
float | 单精度浮点数 | 4 个字节 |
double | 双精度浮点数 | 8 个字节 |
decimal(M, D) | 压缩的“严格”定点数 | M + 2 个字节 |
实数类型通常用于存储有小数的场景下,比如金额,重量等
博主在使用 MySQL 中这几个类型使用较少,这里给大家提供一些金额类字段存储的设计思路
我们存储金额一般会精确到分,比如 12.54 元,那么在存储的时候我们可以用整型,将 12.54 * 100 存储数据库中,取出的时候再进行相应的转化。有的同学可能会有疑问,这样做不是很麻烦。为什么这么做,这里就涉及到计算的精度问题了,如果计算时发现需要四舍五入,那么就可以考虑将数值乘以相应的倍数,100、1000 倍
类型 | 长度范围 | 字节数 |
---|---|---|
char(M) | 0 <= M <=255 | M 个字节 |
varchar(M) | 0 <= M <= 65535 | M + 1 个字节 |
enum | 1 <= M <= 65535 | 1或者2 个字节 |
tinytext | 0 <= M <=255 | M + 2 个字节 |
text | 0 <= M <= 65535 | M + 2 个字节 |
mediumtext | 0 <= M <= 16777215 | M + 3 个字节 |
longtext | 0 <= M <= 4294967295 | M + 4 个字节 |
工作中常用的就是 char、varchar 和 text 类型
char
1
个字符。varchar
char 和 varchar 如何选择
1、存储很短的信息。比如门牌号码101,201……这样很短的信息应该用char,因为varchar还要占个byte用于存储信息长度,本来打算节约存储的,结果得不偿失。
2、固定长度的。比如使用uuid作为主键,那用char应该更合适。因为他固定长度,varchar动态根据长度的特性就消失了,而且还要占个长度信息。
3、十分频繁改变的column。因为varchar每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的,那就要有很多的精力用于计算,而这些对于char来说是不需要的。
扩展:
4.0版本以下,varchar(20),指的是20字节,如果存放UTF8汉字时,只能存6个(每个汉字3字节) 5.0版本以上,varchar(20),指的是20字符,无论存放的是数字、字母还是UTF8汉字(每个汉字3字节),都可以存放20个,最大大小是65532字节
gbk:每个字符最多占用2个字节 utf8:每个字符最多占用3个字节
text
text 通常用于存储大文本,比如文章,评论等
以下设计规范出自阿里巴巴开发手册
(1 表示是,0 表示否)。
说明:任何字段如果为非负数,必须是 unsigned。
注意:POJO 类中的任何布尔类型的变量,都不要加 is 前缀,所以,需要在设置
从 is_xxx 到 Xxx 的映射关系。数据库表示是与否的值,使用 tinyint 类型,坚持 is_xxx 的
命名方式是为了明确其取值含义与取值范围。
正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。
出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
说明:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库名、
表名、字段名,都不允许出现任何大写字母,避免节外生枝。
正例:aliyun_admin,rdc_config,level3_name
反例:AliyunAdmin,rdcConfig,level_3_name
说明:表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于 DO 类名也是单数
形式,符合表达习惯。
说明:pk_ 即 primary key;uk_ 即 unique key;idx_ 即 index 的简称。
说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不
正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。
度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索
引效率。
说明:其中 id 必为主键,类型为 bigint unsigned、单表时自增、步长为 1。gmt_create,
gmt_modified 的类型均为 datetime 类型,前者现在时表示主动创建,后者过去分词表示被
动更新。
正例:alipay_task / force_project / trade_config
1)不是频繁修改的字段。
2)不是 varchar 超长字段,更不能是 text 字段。
正例:商品类目名称使用频率高,字段长度短,名称基本一成不变,可在相关联的表中冗余存
储类目名称,避免关联查询。
说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
索速度。
常用 SQL 语句可以看我之前写的一篇博客,里面详细记录了常用的查询语句