整数类型

MySQL 整数类型如下表所示。

类型 存储空间(字节) M 默认值
(显示宽度)
范围(有符号) 范围(无符号)
TINYINT (M) 1 TINYINT (4) (-128,127) (0,255)
SMALLINT (M)
2 SMALLINT (6) (-32 768,32 767) (0,65 535)
MEDIUMINT (M) 3 MEDIUMINT (9) (-8 388 608,8 388 607) (0,16 777 215)
INT (M) 或 INTEGER (M) 4 INT (11) (-2 147 483 648,2 147 483 647) (0,4 294 967 295)
BIGINT (M) 8 BIGINT (20) (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615)

使用整数类型需要注意该类型支持的使用范围,防止出现越界情况,比如我们在使用自增主键的时候,一般推荐使用 BIGINT 类型。

  • 存储空间:存储需要占用多少字节(占用字节 bytes)。
  • M:表示最大显示宽度,建表若设置 zerofill(0 填充),会在数字前面补充 0,若没有设置 0 填充,那么直接显示,不会影响存储空间大小。

    浮点类型

MySQL 浮点类型如下表所示。

类型 存储空间
(字节)
范围(有符号) 范围(无符号) 用途
FLOAT [(M, D)] 4 (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 单精度
浮点数值
DOUBLE [(M, D)] 8 (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度
浮点数值
DECIMAL [(M[, D])] 对 DECIMAL (M,D) ,如果 M>D,为 M+2 否则为 D+2 依赖于 M 和 D 的值 依赖于 M 和 D 的值 小数值
  • 注意:财务系统必须使用 DECIMAL。
  • FLOAT [(M,D)] [UNSIGNED] [ZEROFILL]
    • 单精度浮点数,有符号值的范围是(-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38),无符号值的范围是 0,(1.175 494 351 E-38,3.402 823 466 E+38),这些是基于 IEEE 标准的理论限制,实际范围可能会略小,具体取决于您的硬件或操作系统;
    • M 是总位数,D 是小数点后的位数,如果省略 MD,则将值存储到硬件允许的极限,单精度浮点数的精度约为小数点后 7 位;
    • FLOAT (M, D) 是非标准的 MySQL 扩展。从 MySQL 8.0.17 开始,该语法已被弃用,您应该期望在将来的 MySQL 版本中删除对该语法的支持;
    • 如果指定了 UNSIGNED,则不允许使用负值。从 MySQL 8.0.17 开始,对于 FLOAT 类型的列,UNSIGNED 属性已被弃用,您应该期望在将来的 MySQL 版本中删除对它的支持;
    • 使用 FLOAT 可能会给您带来一些意想不到的问题,因为 MySQL 中的所有计算都是以双精度进行的。
  • DOUBLE [(M,D)] [UNSIGNED] [ZEROFILL]
    • 双精度浮点数,有符号值的范围是(-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308),无符号值的范围是 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308),这些是基于 IEEE 标准的理论限制,实际范围可能会略小,具体取决于您的硬件或操作系统;
    • M 是总位数,D 是小数点后的位数,如果省略 MD,则将值存储到硬件允许的极限,双精度浮点数的精度大约为 15 个小数位;
    • DOUBLE (M, D) 是一个非标准的 MySQL 扩展。从 MySQL 8.0.17 开始,该语法已被弃用,您应该期望在将来的 MySQL 版本中删除对该语法的支持;
    • 如果指定了 UNSIGNED,则不允许使用负值。从 MySQL 8.0.17 开始,对于 DOUBLE 类型的列,UNSIGNED 属性已被弃用,您应该期望在将来的 MySQL 版本中删除对它的支持。
  • DECIMAL [(M[,D])] [UNSIGNED] [ZEROFILL]
    • 一个包装好的 “精确 “定点数字。
    • M 是总的位数(精度),D 是小数点后的位数(比例)。小数点和负号不计入 M 中。如果 D 为 0,数值没有小数点或小数部分。DECIMAL 的最大位数(M)是 65。支持的小数(D)的最大位数为30。如果省略 D,则默认为 0,省略 M,则默认为 10。(DECIMAL 字符的文本长度也有限制,参考: Section 12.25.3, “Expression Handling”);
    • 如果指定了 UNSIGNED,则不允许使用负值。从 MySQL 8.0.17 开始,UNSIGNED 属性对于 DECIMAL (和任何同义词)类型的列来说是不适用的,你应该期望在未来的 MySQL 版本中删除对它的支持;
    • 所有带 DECIMAL 列的基本计算 (+, -, *, /) 都是以 65 位数的精度来完成的。

      特性描述

      SIGNED & UNSIGNED

整数类型分为有符号(signed)和无符号(unsigned)类型,在创建表结构的时候可以指定。需要注意,有符号和无符号的整数类型,它的范围是不一样的。

  1. mysql> create table t1(a int unsigned, b int unsigned);
  2. Query OK, 0 rows affected (0.14 sec)
  3. mysql> insert into t1 values(1, 2);
  4. Query OK, 1 row affected (0.03 sec)

字段设置为无符号的,需要注意,执行如下 SQL ,会出现越界的情况。一般情况下使用 INT 时,推荐有符号数,使用无符号数只是比原来多一倍的取值,数量级上没有改变。

  1. mysql> select a - b from t1;
  2. ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(`burn_test`.`test_unsigned`.`a` - `burn_test`.`test_unsigned`.`b`)'

我们新建了一个测试表,两个字段均为 unsigned int 型,插入两个值,然后做减法运算时报错,并不是我们想要的结果,正常情况 1-2=-1,但是当数据类型为 unsigned 时,MySQL 运算的结果也是 unsigned,而 -1 已经超出了 unsigned 范围,所以会报错。

如何解决这个问题呢,设置一下 sql_mode 就可以解决这个问题:

  1. mysql> set sql_mode = 'no_unsigned_subtraction'; -- 这样就可以得到负数
  2. Query OK, 0 rows affected (0.00 sec)
  3. mysql> select a - b from t1;
  4. +-------+
  5. | a - b |
  6. +-------+
  7. | -1 |
  8. +-------+
  9. 1 row in set (0.00 sec)

sql_mode 的设置是有风险的,因为可以通过这个设置允许一些非法的操作。如将 null 值插入 not null 字段,将非法的日期 2017-12-32 插入到日期字段,一般在生产环境都都设置为严格模式,所以在不熟悉 MySQL 底层机制或者不了解 unsigned 原理时,慎用它。

INT (M)

INT(M) 中的 M 指的是该字段能输出显示的最大数字长度,不表示数字存储的长度上限,不会影响存储空间大小,M 本身没有意义,需要配合 zerofill 使用才有意义。当存储数字的长度超过 M 时,按照实际存储的数字显示。

比如,创建一个 M 是 3 的列,插入两条数据。

  1. mysql> create table t2(a int(3));
  2. Query OK, 0 rows affected (0.01 sec)
  3. mysql> insert into t2 values(1),(111),(1111);
  4. Query OK, 3 rows affected (0.00 sec)
  5. Records: 3 Duplicates: 0 Warnings: 0
  6. mysql> select * from t2;
  7. +------+
  8. | a |
  9. +------+
  10. | 1 |
  11. | 111 |
  12. | 1111 |
  13. +------+
  14. 3 rows in set (0.00 sec)

在创建字段的时候如果指定了 zerofill 表示当存储的数字长度 < M 时,用数字 0 填充左边,直至补满长度 M。

  1. mysql> create table t3(a int(3) zerofill);
  2. Query OK, 0 rows affected (0.01 sec)
  3. mysql> insert into t3 values(1),(111),(1111);
  4. Query OK, 3 rows affected (0.01 sec)
  5. Records: 3 Duplicates: 0 Warnings: 0
  6. mysql> select * from t3;
  7. +------+
  8. | a |
  9. +------+
  10. | 001 |
  11. | 111 |
  12. | 1111 |
  13. +------+
  14. 3 rows in set (0.00 sec)

所以一般情况下,我们不需要指定 M 值。

不同的数据类型对长度的处理也不一样:

  • 整数类型
    • 这里显示的长度和数据类型的取值范围是没有任何关系的,显示长度只是指明 MySQL 最大可能显示的数字个数,数值的位数小于指定的长度时会由空格填充(前提是指定了 zerofill);
    • 如果插入了大于显示长度的值,只要该值不超过该类型的取值范围,数值依然可以插入,而且能够显示出来;
    • 如果你不设置宽度,系统将添加默认的宽度 TINYINT (4)、SMALLINT (6)、MEDIUMINT (9)、INT (11)、 BIGINT (20),这些默认的宽度是跟该类型的取值范围长度相关。
  • 字符串类型:对于字符串类型,这个长度才真的用上了。不管是 CHAR 还是 VARCHAR,长度都定义了字符串的最大长度;例如 password varchar(20),如果你输入了一个 21 个字符的密码,在严格模式下会提示长度越界异常;
  • 浮点和日期等数据类型:对数据的宽度没有要求,一般也不设置,默认是 0。

    总结

  • 整数类型不需要指定显示宽度 (M),没有意义;

  • 如果要使用浮点类型,建议使用双精度浮点数(DOUBLE);
  • 浮点类型不需要指定显示宽度 (M, D),没有意义;
  • 财务相关的字段必须使用 DECIMAL,其他浮点类型精度不够,容易出现偏差。

详细内容参考 MySQL 8.0 官方文档:Numeric Data Type Syntax

作者:殷建卫 链接:https://www.yuque.com/yinjianwei/vyrvkf/sqac50 来源:殷建卫 - 架构笔记 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。