MySQL 支持多种类型,大致可以分为三类:数值、日期 / 时间和字符串 (字符) 类型。
数值类型:
类型 | 大小 | 范围(有符号) | 范围(无符号) | 用途 |
---|---|---|---|---|
TINYINT(tiny Int) | 1 Bytes | (-128,127) | (0,255) | 小整数值 |
SMALLINT(small Int) | 2 Bytes | (-32 768,32 767) | (0,65 535) | 大整数值 |
MEDIUMINT(medium int) | 3 Bytes | (-8 388 608,8 388 607) | (0,16 777 215) | 大整数值 |
INT 或 INTEGER(integer) | 4 Bytes | (-2 147 483 648,2 147 483 647) | (0,4 294 967 295) | 大整数值 |
BIGINT(big int) | 8 Bytes | ... | (0,18 446 744 073 709 551 615) | 极大整数值 |
FLOAT (float) | 4 Bytes | ... | 0,(1.175 494 351 E-38,3.402 823 466 E+38) | 单精度 浮点数值 |
DOUBLE(double) | 8 Bytes | ... | ... | 双精度 浮点数值 |
unsigned
属性,表示无符号整数。日期和时间类型:
类型 | 大小(bytes) | 格式 |
---|---|---|
DATE(date) | 3 | YYYY-MM-DD |
TIME (time) | 3 | HH:MM:SS |
YEAR(year) | 1 | YEAR |
DATETIME(date time) | 8 | YYYY-MM-DD hh:mm:ss |
TIMESTAMP(time stemp) | 4 | YYYY-MM-DD hh:mm:ss |
尽量使用 TIMESTAMP,空间效率高于 DATETIME。
字符串类型:
类型 | 大小(bytes) | 用途 |
---|---|---|
CHAR(char) | 0-255 | 定长字符串 |
VARCHAR(varchar) | 0-65535 | 变长字符串 |
TINYBLOB(tiny blob) | 0-255 | 不超过 255 个字符的二进制字符串 |
TINYTEXT(tiny text) | 0-255 | 短文本字符串 |
BLOB(blob) | 0-65 535 | 二进制形式的长文本数据 |
TEXT(text) | 0-65 535 | 长文本数据 |
MEDIUMBLOB(medium blob) | 0-16 777 215 | 二进制形式的中等长度文本数据 |
MEDIUMTEXT(meidum text) | 0-16 777 215 | 中等长度文本数据 |
LONGBLOB(long blob) | 0-4 294 967 295 | 二进制形式的极大文本数据 |
LONGTEXT(long text) | 0-4 294 967 295 | 极大文本数据 |
注意:
char(n)
和varchar(n)
中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。datetime
能保存大范围的值,从 1001~9999 年,精度为秒。把日期和时间封装到了一个整数中,与时区无关,使用 8 字节存储空间。timestamp
和 UNIX 时间戳相同,只使用 4 字节的存储空间,范围比 DATETIME 小得多,只能表示 1970 ~2038 年,并且依赖于时区。范式只是给了我们一个参考,我们更多的是要根据项目实际情况设计表结构。
第一范式(1NF):遵循原子性。即,表中字段的数据,不可以再拆分。
先看一个不符合第一范式的表结构,如下:
员工编码 | 姓名 | 年龄 |
---|---|---|
001 | 销售部小张 | 28 |
002 | 运营部小黄 | 25 |
003 | 技术部小高 | 22 |
在这一个表中的,姓名 字段下的数据是可以再进行拆分的,因此它不符合第一范式,那怎么样才符合第一范式呢?如下:
员工编码 | 部门 | 姓名 | 年龄 |
---|---|---|---|
001 | 销售部 | 小张 | 28 |
002 | 运营部 | 小黄 | 25 |
003 | 技术部 | 小高 | 22 |
那是否遵循第一范式就一定是好的呢?如下:
员工编码 | 姓名 | 地址 |
---|---|---|
001 | 小张 | 江西省南昌市东湖区 |
002 | 小黄 | 广东省佛山市禅城区 |
003 | 小高 | 湖北省武汉市新洲区 |
通过观察上述表结构,我们发现,地址是可以再进一步拆分的,比如:
员工编码 | 姓名 | 省 | 市 | 区 |
---|---|---|---|---|
001 | 小张 | 江西省 | 南昌市 | 东湖区 |
002 | 小黄 | 广东省 | 佛山市 | 禅城区 |
003 | 小高 | 湖北省 | 武汉市 | 新洲区 |
虽然拆分后,看上去更符合第一范式了,但是如果项目就只需要我们输出一个完整地址呢?那明显是表在没拆分的时候会更好用。
所以范式只是给了我们一个参考,我们更多的是要根据项目实际情况设计表结构。
第二范式(2NF):在满足第一范式的情况下,遵循唯一性,消除部分依赖。即,表中任意一个主键或任意一组联合主键,可以确定除该主键外的所有的非主键值。
再通俗点讲就是,一个表只能描述一件事情。
我们用一个经典案例进行解析。
学号 | 姓名 | 年龄 | 课程名称 | 成绩 | 学分 |
---|---|---|---|---|---|
001 | 小张 | 28 | 语文 | 90 | 3 |
001 | 小张 | 28 | 数学 | 90 | 2 |
002 | 小黄 | 25 | 语文 | 90 | 3 |
002 | 小黄 | 25 | 语文 | 90 | 3 |
003 | 小高 | 22 | 数学 | 90 | 2 |
我们先分析一下表结构。
那我们应该如何调整表结构,让它能复合第二范式的要求呢?
我们可以基于上述的三种主键的可能,拆分成 3 张表,保证一张表只描述一件事情。
学生表 - 学号做主键
学号 | 姓名 | 年龄 |
---|---|---|
001 | 小张 | 28 |
002 | 小黄 | 25 |
003 | 小高 | 22 |
课程表 - 课程名称做主键
课程名称 | 学分 |
---|---|
语文 | 3 |
数学 | 2 |
成绩表 - 学号和课程名称做联合主键
学号 | 课程名称 | 成绩 |
---|---|---|
001 | 语文 | 90 |
001 | 数学 | 90 |
002 | 语文 | 90 |
002 | 语文 | 90 |
003 | 数学 | 90 |
这时候我们可能会想,为什么我们就要遵循第二范式呢?不遵循第二范式会造成什么样的后果呢?
第三范式(3NF):在满足第二范式的情况下,消除传递依赖。即,在任一主键都可以确定所有非主键字段值的情况下,不能存在某非主键字段 A 可以获取 某非主键字段 B。
即:非主键列只依赖于主键,不依赖于其他非主键。
仍然用一个经典例子来解析:
学号 | 姓名 | 班级 | 班主任 |
---|---|---|---|
001 | 小黄 | 一年级(1)班 | 高老师 |
这个表中,学号是主键,它可以唯一确定姓名、班级、班主任,符合了第二范式,但是在非主键字段中,我们也可以通过班级推导出该班级的班主任,所以它是不符合第三范式的。
那怎么设计表结构,才是符合第三范式的呢?
通过把班级与班主任的映射关系另外做成一张映射表,我们就成功地消除了表中的传递依赖了。
姓名可能相同,所以通过姓名不能确定班级,所以无需拆分。
除了三大范式外,还有BC范式和第四范式,但其规范过于严苛,在生产中往往使用不到。
名称 | 优点 | 缺点 |
---|---|---|
范式 | 范式化的表减少了数据冗余,数据表更新操作快、占用存储空间少。 | 查询时通常需要多表关联查询,更难进行索引优化 |
反范式 | 反范式的过程就是通过冗余数据来提高查询性能,可以减少表关联和更好进行索引优化 | 存在大量冗余数据,并且数据的维护成本更高 |
所以在平时工作中,我们通常是将范式和反范式相互结合使用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。