- 原文地址:https://github.com/shirayner/java-knowledge-hierarchy/tree/master/doc/Mysql
- 此系列博客是站在大牛的肩膀上所做的总结,主要是方便建立自己的知识体系。所参考的文章会在每篇博客的参考资料部分列出
文章目录
前言
MySQL支持多种数据类型,主要有数值类型、日期/时间类型、字符串类型和二进制类型:
- 数值类型:
- 整数类型:TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT
- 浮点小数类型:FLOAT和DOUBLE
- 定点小数类型:DECIMAL
- 日期/时间类型:包括YEAR、TIME、DATE、DATETIME和TIMESTAMP。
- 字符串类型:
- 文本字符串:包括CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET等。
- 二进制字符串:包括BIT、BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB。
一、数值类型
MySQL提供多种数值数据类型,不同的数据类型提供的取值范围不同,可以存储的值的范围越大,其所需要的存储空间也就越大,因此要根据实际需求选择适合的数据类型。
1.整数类型
MySQL主要提供的整数类型有:TINYINT、SMALLINT、MEDIUMINT、INT(INTEGER)、BIGINT。
整数类型的字段属性可以添加 AUTO_INCREMENT
自增约束条件。
1.1 内存大小与取值范围
Table 11.1 Required Storage and Range for Integer Types Supported by MySQL
Type | Storage (Bytes) | Minimum Value Signed | Minimum Value Unsigned | Maximum Value Signed | Maximum Value Unsigned |
---|---|---|---|---|---|
TINYINT |
1 | -128 | 0 | 127 | 255 |
SMALLINT |
2 | -32768 | 0 | 32767 | 65535 |
MEDIUMINT |
3 | -8388608 | 0 | 8388607 | 16777215 |
INT |
4 | -2147483648 | 0 |
2147483647 |
4294967295 |
BIGINT |
8 | -263 | 0 |
263-1 | 264-1 |
1.2 显示宽度
通过整数类型关键字后面的括号内的整数值,可以指定该字段的最大显示宽度,如 int(8) 表示最大有效显示宽度为8。
显示宽度有两个作用:
(1)对齐填充
当整型字段的值的实际个数小于指定显示宽度时,会由空格从左侧填满宽度。
(2)限制位数
只能插入位数小于显示宽度的值
例如:
mysql> create table t1(a TINYINT, b SMALLINT, c MEDIUMINT, d INT, e BIGINT, f TINYINT unsigned); -- 建表
Query OK, 0 rows affected (0.30 sec)
mysql> desc t1; -- 查看默认显示宽度
+-------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+-------+
| a | tinyint(4) | YES | | NULL | |
| b | smallint(6) | YES | | NULL | |
| c | mediumint(9) | YES | | NULL | |
| d | int(11) | YES | | NULL | |
| e | bigint(20) | YES | | NULL | |
| f | tinyint(3) unsigned | YES | | NULL | |
+-------+---------------------+------+-----+---------+-------+
6 rows in set (0.00 sec)
mysql> insert into t1(a) values(1234); -- 有符号,长度等于显示宽度,无法插入
ERROR 1264 (22003): Out of range value for column 'a' at row 1
mysql> insert into t1(a) values(123); -- 有符号,长度小于显示宽度,可插入
Query OK, 1 row affected (0.01 sec)
mysql> insert into t1(f) values(1234); -- 无符号,长度等于显示宽度,无法插入
ERROR 1264 (22003): Out of range value for column 'f' at row 1
2.浮点数类型和定点数类型
MySQL中使用浮点数和定点数表示小数。
浮点类型有两种:单精度浮点类型(FLOAT)和双精度浮点类型(DOUBLE)。定点类型只有一种:DECIMAL。
浮点类型和定点类型都可以用(M,D)来表示,其中M称为精度,表示总共的位数;D称为标度,表示小数的位数。
MySQL数据类型 | 存储需求 | 含义 |
---|---|---|
float(m,d) | 4字节 | 单精度浮点型 m总个数,d小数位 |
double(m,d) | 8字节 | 双精度浮点型 m总个数,d小数位 |
DECIMAL(M,D) | M+2个字节 | 压缩的“严格”定点数 |
注意:
(1)不论是定点类型还是浮点类型,如果用户指定的精度值超过精度范围,则会进行四舍五入的处理。
(2)在MySQL中,在对精度要求比较高的时候(如货币、科学数据等),尽量选择使用DECIMAL类型。另外,两个浮点数在进行减法和比较运算的时候容易出问题,因此在使用浮点数类型时需要注意,并尽量避免做浮点数比较。
(3)DECIMAL 类型的数据当插入的小数部分有多余的位数,截断后插入数据库;当插入的整数部分的值超过了其表示范围则不会插入到数据库。
示例:
create table t2(a FLOAT(4,1), b DOUBLE(4,1), c DECIMAL(4,1));
insert into t2 values(4.23,4.26,4.234);
二、日期和时间类型
每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。
类型 | 大小 (字节) | 范围 | 格式 | 用途 |
---|---|---|---|---|
DATE | 3 | 1000-01-01~9999-12-31 | YYYY-MM-DD | 日期值 |
TIME | 3 | ‘-838:59:59’~‘838:59:59’ | HH:MM:SS | 时间值或持续时间 |
YEAR | 1 | 1901~2155 | YYYY | 年份值 |
DATETIME | 8 | 1000-01-01 00:00:00~9999-12-31 23:59:59 | YYYY-MM-DD HH:MM:SS | 混合日期和时间值 |
TIMESTAMP | 8 | 1970-01-01 00:00:00~2037 年某时 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
示例:
create table t3( a YEAR);
insert into t3 values( 2015),(' 2015');
mysql> select * from t3;
+------+
| a |
+------+
| 2015 |
| 2015 |
+------+
2 rows in set (0.00 sec)
mysql> insert into t3 values('2288');
ERROR 1264 (22003): Out of range value for column 'a' at row 1
由上述结果可看出:
- 插入值无论是数值型还是字符串型,都可以被正确地存储到数据库中;
- 但是假如插入值超过了YEAR类型的取值范围,则插入失败。
TIMESTAMP 和 DATATIME 除了存储字节和支持的范围不同外,还有一个最大的区别就是:
- DATETIME 在存储日期数据时,按实际输入的格式存储,即输入什么就存储什么,与时区无关;
- 而 TIMESTAMP 值的存储是以 UTC (世界标准时间)格式保存的,存储时对当前时区进行转换,检索时再转换回当前时区。即查询时,根据当前时区的不同,显示的时间值是不同的。
三、字符串类型
1.文本字符串
类型 | 大小 | 用途 |
---|---|---|
CHAR | 0-255字节 | 定长字符串 |
VARCHAR | 0-65535 字节 | 变长字符串 |
TINYTEXT | 0-255字节 | 短文本字符串 |
TEXT | 0-65 535字节 | 长文本数据 |
MEDIUMTEXT | 0-16 777 215字节 | 中等长度文本数据 |
LONGTEXT | 0-4 294 967 295字节 | 极大文本数据 |
ENUM | 枚举类型,只能存一个枚举字符串值 | 1或2个字节,取决于枚举值的数目(最大值65535) |
SET | 一个设置,字符串对象可以有零个或多个 SET 成员 | 1、2、3、4或8个字节,取决于集合成员的数量(最多64个成员) |
1.1 CHAR 和 VARCHAR 类型
- CHAR(M) 为固定长度字符串,VARCHAR(M) 是长度可变的字符串.
- CHAR 是固定长度,所以它的处理速度比 VARCHAR 的速度快,但是确定是浪费空间。
- 当检索 CHAR 值时,尾部的空格将被删除掉。VARCHAR 在值保存和检索时尾部的空格仍保留。
- 字符串类型的 M 值是存储的最大字节数,不是显示宽度,如果插入的字符超过了 M 值,则不允许插入。不要与整数类型的 M 值搞混。
1.2 TEXT 类型
TEXT 类型保存非二进制字符串,如文章内容、评论等,当保存或查询 TEXT 列的值时,不删除尾部空格。
1.3 ENUM 类型和 SET 类型
ENUM 与SET 都是枚举类型,不同的是,ENUM 字段只能从定义的列值中选择一个值插入,而 SET 类型的列可从定义的列值中选择多个字符的联合。
2.二进制字符串
类型名称 | 说明 | 存储需求 |
---|---|---|
BIT(M) | 位字段类型 | 大约(M+7)/8个字节 |
BINARY(M) | 固定长度二进制字符串 | M个字节 |
VARBINARY(M) | 可变长度二进制字符串 | M+1个字节 |
TINYBLOB(M) | 非常小的BLOB | L+1个字节,L<2^8 |
BLOB(M) | 小的BLOB | L+2个字节,L<2^16 |
MEDIUMBLOB(M) | 中等大小的BLOB | L+3个字节,L<2^24 |
LONGBLOB(M) | 非常大的的BLOB | L+4个字节,L<2^32 |
BLOB 是二进制字符串,TEXT 是非二进制字符串,两者均可存放大容量的信息。
BLOB 主要存储图片、音频信息等,而 TEXT 只能存储纯文本文件。
但由于现在图片和音频越来越多,检索起来也不方便,所以都不放在数据库,一般放在专门的文件存储服务器上。
四、如何选择数据类型
MySQL提供了大量的数据类型,为了优化存储,提高数据库性能,在不同情况下应使用最精确的类型。在选择数据类型时,在可以表示该字段值的所有类型中,应当使用占用存储空间最少的数据类型。
因为这样不仅可以减少存储(内存、磁盘)空间,从而节省I/O资源(检索相同数据情况下);还可以在数据计算的时候减轻CPU负载。
1. 整数和浮点数
-
如果插入的数据不需要小数部分,则使用整数类型存储数据;如果需要小数部分,则使用浮点数类型。
例如,如果字段取值范围在1~50000,选择SMALLINTUNSIGNED是最好的;假如需要存储带有小数位的值如3.1415926,则需选择浮点数类型。
-
浮点类型包括FLOAT和DOUBLE类型,DOUBLE类型精度比FLOAT高。因此,需要存储精度较高时,需选择DOUBLE类型。
2. 浮点数和定点数
浮点型FLOAT和DOUBLE与定点型DECIMAL的不同点是:
- 数据范围:在长度固定的情况下,浮点型能表示的数据范围更大。
- 精度:
- 当一个字段被定义为浮点类型后,如果插入数据的精度超过该列定义的实际精度,则插入值会被四舍五入到实际定义的精度值,然后插入,四舍五入的过程不会报错。由于浮点型容易因四舍五入产生误差,因此对于精确度要求比较高时,要使用定点型DECIMAL来存储。
- 定点数实际上是以字符串形式存放的,所以定点数可以更精确地保存数据。如果实际插入的数值精度大于实际定义的精度,则MySQL会进行警告(默认的SQLMode下),但是数据按照实际精度四舍五入后插入;如果SQLMode是在TRADITIONAL(传统模式)下,则系统会直接报错,导致数据无法插入。
数据迁移:在数据迁移中,FLOAT(M,D)是非标准SQL定义,数据迁移可能出现问题,最好不要使用。
数值比较:另外,两个浮点型数据进行减法和比较运算时也容易出问题,因此在进行计算的时候,一定要注意,如果要进行数值比较,最好使用定点型DECIMAL。
3. 日期和时间类型
MySQL中选择日期类型的原则如下。
-
根据实际需要选择能够满足应用的最小存储的日期类型。
如果应用只需要记录“年份”,那么用1个字节来存储的YEAR类型完全能够满足,而不需要用4个字节来存储的DATE类型。这样不仅仅能节约存储,更能够提高表的操作效率。
-
如果要记录年月日时分秒,并且记录的年份比较久远,那么最好使用DATETIEM,而不要使用TIMESTAMP。因为TIMESTAMP表示的日期范围比DATETIME要短得多。
-
如果记录的日期需要让不同时区的用户使用,那么最好使用TIMESTAMP,因为日期类型中只有它能够和实际时区相对应。而且当插入一条记录时没有指定TIMESTAMP这个字段值的话,MySQL会把TIMESTAMP字段设为当前的时间。因此当需要在插入记录的同时插入当前时间时,使用TIMESTAMP比较方便。
4. 字符串类型
4.1 CHAR和VARCHAR
CHAR和VARCHAR类型类似,都用来存储字符串,但它们保存和检索的方式不同。
- CHAR属于固定长度的字符类型,而VARCHAR属于可变长度的字符类型。CHAR会自动删除插入数据的尾部空格,VARCHAR不会删除尾部的空格。
- 由于CHAR是固定长度的,所以它的处理速度比VARCHAR快得多,但是其缺点是浪费存储空间,程序需要对行尾空格进行处理,所以对于那些长度变化不大且对查询速度有较高要求的数据可以考虑用CHAR类型来存储。
另外,在MySQL中,不同的存储引擎对CHAR和VARCHAR的使用原则有所不同,概括如下。
- MyISAM存储引擎:建议使用固定长度的数据列代替可变长度的数据列。
- MEMORY存储引擎:目前都使用固定长度的数据行存储,因此无论使用CHAR或VARCHAR列都没有关系,两者都是作为CHAR类型处理。
- InnoDB存储引擎:建议使用VARCHAR类型。对于InnoDB数据表,内部的行存储格式没有区分固定长度和可变长度列(所有数据行都使用指向数据列值的头指针),因此在本质上,使用固定长度的CHAR列不一定比使用可变长度VARCHAR列性能要好。因此,主要的性能因素是数据行使用的存储总量。由于CHAR平均占用的空间多于VARCHAR,因此使用VARCHAR来最小化需要处理的数据行的存储总量和磁盘I/O是比较好的。
4.2 ENUM和SETE
-
NUM只能取单值,它的数据列表是一个枚举集合。它的合法取值列表最多允许有65535个成员。因此,在需要从多个值中选取一个时,可以使用ENUM。
例如,性别字段适合定义为ENUM类型,每次只能从“男”和“女”中取一个值。
-
SET可以取多个值。它的合法取值列表最多允许有64个成员。空字符串也是一个合法的SET值。因此,在需要取多个值的时候,适合使用SET类型。
例如,要存储一个人的特长,最好使用SET类型。ENUM和SET的值是以字符串形式出现的,但在MySQL内部,实际是以数值索引的形式存储它们。
4.3 BLOB和TEXT
- 一般保存少量字符串的时候,可以选择CHAR或者VARCHAR
- 而在保存大文本时,通常会选择使用TEXT或者BLOB,二者之间的主要差别是BLOB能用来保存二进制数据,比如照片、音频信息等;而TEXT只能保存字符数据,比如一篇文章或者日记。
以下是BLOB与TEXT存在的一些常见的问题:
-
碎片整理:BLOB和TEXT值会引起一些性能问题,特别是执行了大量的删除操作时。删除操作会在数据表中留下很大的“空洞”,以后填入这些“空洞”的记录在插入的性能上会有影响。为了提高性能,建议定期使用
OPTIMIZE TABLE
功能对这类表进行碎片整理,避免因为“空洞”导致性能问题。 -
使用合成的(Synthetic)索引来提高大文本字段(BLOB或TEXT)的查询性能。
-
在不必要的时候避免检索大型的BLOB或TEXT值。
例如,SELECT*查询就不是很好的想法,除非能够确定作为约束条件的WHERE子句只会找到所需要的数据行,否则,很可能毫无目的地在网络上传输大量的值。
-
把BLOB或TEXT列分离到单独的表中。
在某些环境中,如果把这些数据列移动到到第二张数据表中,可以把原数据表中的数据列转换为固定长度的数据行格式,那么它就是有意义的。这会减少主表中的碎片,可以得到固定长度数据行的性能优势。它还可以使主数据表在运行SELECT*查询的时候不会通过网络传输大量的BLOB或TEXT值。