MySQL 数据类型

数据类型

整型

TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 分别使用 8, 16, 24, 32, 64 位存储空间,一般情况下越小的列越好。

INT(11) 中的数字只是规定了交互工具显示字符的个数,对于存储和计算来说是没有意义的。

浮点数

FLOAT 和 DOUBLE 为浮点类型,DECIMAL 为高精度小数类型。CPU 原生支持浮点运算,但是不支持 DECIMAl 类型的计算,因此 DECIMAL 的计算比浮点类型需要更高的代价。

FLOAT、DOUBLE 和 DECIMAL 都可以指定列宽,例如 DECIMAL(18, 9) 表示总共 18 位,取 9 位存储小数部分,剩下 9 位存储整数部分。

字符串

主要有 CHAR 和 VARCHAR 两种类型,一种是定长的,一种是变长的。

VARCHAR 这种变长类型能够节省空间,因为只需要存储必要的内容。但是在执行 UPDATE 时可能会使行变得比原来长,当超出一个页所能容纳的大小时,就要执行额外的操作。MyISAM 会将行拆成不同的片段存储,而 InnoDB 则需要分裂页来使行放进页内。

在进行存储和检索时,会保留 VARCHAR 末尾的空格,而会删除 CHAR 末尾的空格。

时间和日期

MySQL 提供了两种相似的日期时间类型:DATETIME 和 TIMESTAMP。

DATETIME

能够保存从 1000 年到 9999 年的日期和时间,精度为秒,使用 8 字节的存储空间。

它与时区无关。

默认情况下,MySQL 以一种可排序的、无歧义的格式显示 DATETIME 值,例如“2008-01-16 22:37:08”,这是 ANSI 标准定义的日期和时间表示方法。

TIMESTAMP

和 UNIX 时间戳相同,保存从 1970 年 1 月 1 日午夜(格林威治时间)以来的秒数,使用 4 个字节,只能表示从 1970 年到 2038 年。

它和时区有关,也就是说一个时间戳在不同的时区所代表的具体时间是不同的。

MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提供了 UNIX_TIMESTAMP() 函数把日期转换为 UNIX 时间戳。

默认情况下,如果插入时没有指定 TIMESTAMP 列的值,会将这个值设置为当前时间。

应该尽量使用 TIMESTAMP

  • DATETIME 类型与时区无关,即没有时区信息。当更换时区后,比如服务器更换地址或者更换客户端连接时区设置,就会导致从数据库中读出的时间错误。

    TIMESTAMP 类型和时区有关。TIMESTAMP 类型字段的值会随着服务器时区的变化而变化,自动换算成相应的时间

  • TIMESTAMP 只需要使用 4 个字节的存储空间,但 DATETIME 需要耗费 8 个字节的存储空间。但是,这样同样造成了一个问题,TIMESTAMP 表示的时间范围更小。

    • DATETIME :1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
    • TIMESTAMP: 1970-01-01 00:00:00 ~ 2037-12-31 23:59:59

    注意 5.6.4 之后的 MySQL 多出了一个需要 0 ~ 3 字节的小数位。DATETIME 和 TIMESTAMP 会有几种不同的存储空间占用。

数值型时间戳

时间戳的定义是从一个基准时间 [ 1970-1-1 00:00:00 +0:00 ] 开始算起,用整数表示,以秒计时,随着时间的流逝这个时间整数不断增加。

一个数值,就可以完美地表示时间了,而且这个数值是一个绝对数值,即无论的身处地球的任何角落,这个表示时间的时间戳,都是一样的,生成的数值都是一样的,并且没有时区的概念。

MySQL 中可以使用 int 或者 bigint 类型的时间戳来表示时间。

小结:

日期类型 存储空间 日期格式 日期范围 时区问题
DATETIME 8 字节 yyyy-MM-dd HH:mm:ss 1000-01-01 00:00:00 ~
9999-12-31 23:59:59
存在
TIMESTAMP 4 字节 yyyy-MM-dd HH:mm:ss 1970-01-01 00:00:00 ~
2037-12-31 23:59:59
不存在
时间戳 4 字节 数值 1970-01-01 00:00:00 之后的时间 不存在