MySQL 数据类型

2022/3/5 19:15:18

本文主要是介绍MySQL 数据类型,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

转自详解 MySQL 数据类型,内容上稍作修改。

整型

数据类型 字节数 带符号最小值 带符号最大值 不带符号最小值 不带符号最大值
TINYINT 1 -128 127 0 255
SMALLINT 2 -32768 32767 0 65535
MEDIUMINT 3 -8388608 8388607 0 16777215
INT 4 -2147483648 2147483647 0 4294967295
BIGINT 8 -9223372036854775808 9223372036854775807 0 18446744073709551616

从实际开发的角度,我们一定要为合适的列选取合适的数据类型,即到底用不用得到这种数据类型?举个例子:

  • 一个枚举字段如果只有 0 和 1 两个枚举值,那么选用 TINYINT 就足够了,但在开发场景下却使用了 BIGINT,这就造成了资源浪费
  • 假使该数据表中有 100W 数据,那么总共浪费了 700W 字节也就是 6.7M 左右,如果更多的表这么做了,那么浪费得更多

运行下列 SQL 语句:

drop table if exists test_tinyint;
create table test_tinyint (
    num tinyint
);

insert into test_tinyint values(-100);
insert into test_tinyint values(255);

执行第 7 行的代码时候报错 Out of range value for column 'num' at row 1,即插入的数字范围越界了,这说明MySQL 中整型默认是带符号的

把第 3 行的 num 字段定义改为 num tinyint unsigned,第 7 的插入就不会报错了,但是第 6 行的插入-100 会报错,因为无符号整型是无法表示负数的。

整型(N)形式

有时,我们会碰到有些定义整型的写法是 int(11)。int(N) 我们只需要记住两点:

  • 无论 N 等于多少,int 永远占 4 个字节
  • N 表示的是显示宽度,默认补足空白(设置了 unsigned zerofill 之后用 0 补足),超过宽度时无视长度直接显示整个数字
drop table if exists test_int_width;
create table test_int_width (
    a int(5),
    b int(5) unsigned,
    c int(5) unsigned zerofill,
    d int(8) unsigned zerofill
);

insert into test_int_width values(1, 1, 1, 1111111111);

select * from test_int_width;
+------+------+-------+------------+
| a    | b    | c     | d          |
+------+------+-------+------------+
|    1 |    1 | 00001 | 1111111111 |
+------+------+-------+------------+
1 row in set (0.00 sec)

浮点型

数据类型 字节数 备注
float 4 单精度浮点型
double 8 双精度浮点型

以 float 为例:

drop table if exists test_float;
create table test_float (
    num float(5, 2)
);

insert into test_float values(1.233);
insert into test_float values(1.237);
insert into test_float values(10.233);
insert into test_float values(100.233);
insert into test_float values(1000.233);
insert into test_float values(10000.233);
insert into test_float values(100000.233);

select * from test_float;
+--------+
| num    |
+--------+
|   1.23 |
|   1.24 |
|  10.23 |
| 100.23 |
+--------+
4 rows in set (0.00 sec)

float(M,D)、double(M、D) 中:

  • D 表示浮点型数据小数点之后的精度,假如超过 D 位则四舍五入,所以 1.233 四舍五入为 1.23,1.237 四舍五入为 1.24
  • M 表示浮点型数据总共的位数,M 为 5 表示总共支持五位,即小数点前只支持三位数,所以我们并没有看到 1000.23、10000.233、100000.233 这三条数据的插入,因为插入都报错了(Out of range value for column 'num' at row 1

当我们不指定 M、D 的时候,会按照实际的精度来处理。

定点型

定点型即 decimal 类型,有了浮点型为什么我们还需要定点型?写一段 SQL 看一下就明白了:

drop table if exists test_decimal;
create table test_decimal (
    float_num float(10, 2),
    double_num double(20, 2),
    decimal_num decimal(20, 2)
);

insert into test_decimal values(1234567.66, 1234567899000000.66, 1234567899000000.66);
insert into test_decimal values(1234567.66, 12345678990000000.66, 12345678990000000.66);

select * from test_decimal;
+------------+----------------------+----------------------+
| float_num  | double_num           | decimal_num          |
+------------+----------------------+----------------------+
| 1234567.62 |  1234567899000000.80 |  1234567899000000.66 |
| 1234567.62 | 12345678990000000.00 | 12345678990000000.66 |
+------------+----------------------+----------------------+
2 rows in set (0.00 sec)

看到 float、double 类型存在精度丢失问题,即写入数据库的数据未必是插入数据库的数据,而 decimal 无论写入数据中的数据是多少,都不会存在精度丢失问题,这就是我们要引入 decimal 类型的原因,decimal 类型常见于银行系统、互联网金融系统等对小数点后的数字比较敏感的系统中。

最后讲一下 decimal 和 float/double 的区别,个人总结主要体现在两点上:

  • float/double 在 db 中存储的是近似值,而 decimal 则是以字符串形式进行保存的
  • decimal(M,D) 的规则和 float/double 相同,但区别在 float/double 在不指定 M、D 时默认按照实际精度来处理而 decimal 在不指定 M、D 时默认为 decimal(10, 0)

日期类型

MySQL 支持五种形式的日期类型:date、time、year、datetime、timestamp:

数据类型 字节数 格式 备注
date 3 yyyy-MM-dd 存储日期值
time 3 HH:mm:ss 存储时分秒
year 1 yyyy 存储年
datetime 8 yyyy-MM-dd HH:mm:ss 存储日期 + 时间
timestamp 4 yyyy-MM-dd HH:mm:ss 存储日期 + 时间,可作时间戳
drop table if exists test_time;
create table test_time (
    date_value date,
    time_value time,
    year_value year,
    datetime_value datetime,
    timestamp_value timestamp
);

insert into test_time values(now(), now(), now(), now(), now());

select * from test_time;
+------------+------------+------------+---------------------+---------------------+
| date_value | time_value | year_value | datetime_value      | timestamp_value     |
+------------+------------+------------+---------------------+---------------------+
| 2022-03-05 | 16:05:37   |       2022 | 2022-03-05 16:05:37 | 2022-03-05 16:05:37 |
+------------+------------+------------+---------------------+---------------------+
1 row in set (0.00 sec)

这里重点关注一下 datetime 与 timestamp 两种类型的区别:

  • 上面列了,datetime 占 8 个字节,timestamp 占 4 个字节
  • 由于字节数的区别,datetime 与 timestamp 能存储的时间范围也不同,datetime 的存储范围为 1000-01-01 00:00:00——9999-12-31 23:59:59,timestamp 存储的时间范围为 19700101080001——20380119111407
  • datetime 默认值为空,当插入的值为 null 时,该列的值就是 null;timestamp 默认值不为空,当插入的值为 null 的时候,MySQL 会取当前时间
  • datetime 存储的时间与时区无关,timestamp 存储的时间及显示的时间都依赖于当前时区

在实际工作中,一张表往往我们会有两个默认字段,一个记录创建时间而另一个记录最新一次的更新时间,这种时候可以使用 timestamp 类型来实现。

char 和 varchar 类型

说到 MySQL 字符型,我们最熟悉的应该就是 char 和 varchar 了,关于 char 和 varchar 的对比,我总结一下:

  1. char 是固定长度字符串,其长度范围为 0~255 且与编码方式无关,无论字符实际长度是多少,都会按照指定长度存储,不够的用空格补足;varchar 为可变长度字符串,在 utf8 编码的数据库中其长度范围为 0~21844
  2. char 实际占用的字节数即存储的字符所占用的字节数,varchar 实际占用的字节数为存储的字符 +1 或 +2 或 +3(见 varchar 型数据占用空间大小及可容纳最大字符串限制探究)
  3. MySQL 处理 char 类型数据时会将结尾的所有空格处理掉而 varchar 类型数据则不会

关于第一点、第二点,稍后专门解释,关于第三点,写一下 SQL 验证一下:

drop table if exists test_string;
create table test_string (
    char_value char(5),
    varchar_value varchar(5)
);

insert into test_string values('a', 'a');
insert into test_string values(' a', ' a');
insert into test_string values('a ', 'a ');
insert into test_string values(' a ', ' a ');

select length(char_value), length(varchar_value) from test_string;
+--------------------+-----------------------+
| length(char_value) | length(varchar_value) |
+--------------------+-----------------------+
|                  1 |                     1 |
|                  2 |                     2 |
|                  1 |                     2 |
|                  2 |                     3 |
+--------------------+-----------------------+
4 rows in set (0.00 sec)

可以看到,char 类型数据并不会保留字符串结尾的空格。

varchar 型数据占用空间大小及可容纳最大字符串限制探究

接上一部分,我们这部分来探究一下 varchar 型数据实际占用空间大小是如何计算的以及最大可容纳的字符串为多少,首先要给出一个结论:这部分和具体编码方式有关

先写一段 SQL 创建表,utf8 的编码格式:

drop table if exists test_varchar;
create table test_varchar (
    varchar_value varchar(100000)
) charset=utf8;

执行报错:

Column length too big for column 'varchar_value' (max = 21845); use BLOB or TEXT instead

按照提示,我们把大小改为 21845,执行依然报错:

Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

改为 21844 就不会有问题,因此在 utf8 编码下我们可以知道 varchar(M),M 最大=21844。那么 gbk 呢:

drop table if exists test_varchar;
create table test_varchar (
    varchar_value varchar(100000)
) charset=gbk;

同样报错:

Column length too big for column 'varchar_value' (max = 32767); use BLOB or TEXT instead

把大小改为 32767,也是和 utf8 编码格式一样的报错:

Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

改为 M=32765 不会有问题,那么为什么会这样?分点详细解释一下:

  • MySQL 要求一个行的数据量长度不能超过 65535 即 64K
  • 对于未指定 varchar 字段 not null 的表,会有 1 个字节专门表示该字段是否为 null
  • varchar(M),当 M 范围为 0<=M<=255 时会专门有一个字节记录 varchar 型字符串长度,当 M>255 时会专门有两个字节记录 varchar 型字符串的长度,把这一点和上一点结合,那么 65535 个字节实际可用的为 65535-3=65532 个字节
  • 所有英文无论其编码方式,都占用 1 个字节,但对于 gbk 编码,一个汉字占两个字节,因此最大 M=65532/2=32766;对于 utf8 编码,一个汉字占 3 个字节,因此最大 M=65532/3=21844,解释了实验中的现象
  • 举一反三,对于 utf8mb4 编码方式,1 个字符最大可能占 4 个字节,那么 varchar(M),M 最大为 65532/4=16383,可以自己验证一下

同样的,上面是表中只有 varchar 型数据的情况,如果表中同时存在 int、double、char 这些数据,需要把这些数据所占据的空间减去,才能计算 varchar(M) 型数据 M 最大等于多少

varchar、text 和 blob

最后讲一讲 text 和 blob 两种数据类型,它们的设计初衷是为了存储大数据使用的,因为之前说了,MySQL 单行最大数据量为 64K。

先说一下 text,text 和 varchar 是一组既有区别又有联系的数据类型,其联系在于当 varchar(M) 的 M 大于某些数值时,varchar 会自动转为 text

  • M>255 时转为 tinytext
  • M>500 时转为 text
  • M>20000 时转为 mediumtext

所以过大的内容 varchar 和 text 没有区别,同时 varchar(M) 和 text 的区别在于:

  • 单行 64K 即 65535 字节的空间,varchar 只能用 65532/65533 个字节,但是 text 可以 65535 个字节全部用起来
  • text 可以指定 text(M),但是 M 无论等于多少都没有影响
  • text 不允许有默认值,varchar 允许有默认值

varchar 和 text 两种数据类型,使用建议是能用 varchar 就用 varchar 而不用 text(存储效率高),varchar(M) 的 M 有长度限制,之前说过,如果大于限制,可以使用 mediumtext(16M)或者 longtext(4G)。

至于 text 和 blob,简单过一下就是text 存储的是字符串而 blob 存储的是二进制字符串,简单说 blob 是用于存储例如图片、音视频这种文件的二进制数据的。



这篇关于MySQL 数据类型的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程