MySQL数据类型
MySQL中的数据类型大致分为3种:数字类型、日期类型、字符串类型。
数字类型
MySQL中数字类型可分为两类:
整型:TINYINT(1字节),SMALLINT(2字节),MEDIUNINT(3字节),INT(4字节),BIGINT(8字节);
非整形:FLOAT(4字节),DOUBLE(8字节),DECIMAL(M,D)—— m:总个数,d:小数位;
使用建议
(1)如果确认为无符号,则务必指定为无符号(ungsighed);
(2)使用尽可能小的类型
对于常见的有限集,比如某对象的status或者type,如果用数字类型来表示,使用tinyint就够了
对于对象的id,一般选择为BIGINT
(3)创建数字类型的字段时,不必向创建字符串类型的字段一样指定其长度,为数字类型的字段指定的长度仅仅是为了可视化时的显示长度(display width),对于存储等没有任何效果。如下所示,tinyint(1)中的1并非指定status的长度为1,tinyint类型的字段的长度是固定的1字节。
(4)小数类型选择decimal,禁止使用float和double。
float和double在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不正确的结果。
如果存储的数据范围超过decimal的范围,建议将数据拆成整数和小数分开存储
日期类型
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 | 4字节 | 1970-01-01 00:00:00/2038;结束时间是第2147483647秒,北京时间2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 | YYYYMMDD HHMMSS | 混合日期和时间值,时间戳 |
使用建议
(1)尽量选择恰当的类型:如果只是记录年,则使用YEAR,如果只是记录时间,则使用TIME,不要一概而论地都使用DATATIME
(2)虽然TIMESTAMP具有在创建或更新时自动设置为当前时间的功能,但是这种控制还是交给程序,让MySQL做它应该做的事情,况且,TIMESTAMP只能表示到2038年1月19日,之后呢?所以,建议使用DATATIME这种类型。
(3)关于时区转换
在MySQL只有TIMESTAMP会做时区转换:无论是在读取还是写入
TIMESTAMP
类型的值,都会根据connection的时区(对于Java程序而言,就是Java程序所在的JVM的时区)做转换。也就是说,如果JVM与MySQL不在一个时区,那么JVM去设置一个TIMESTAMP类型的字段值时,MySQL会根据连接获取到JVM所在的时区,然后转换为本地时区的时间值再写入;同样,在JVM去读取TIMESTAMP类型的字段值时,读到的是JVM所在的时区的时间。不要在服务器端做日期时间的字符串格式化(DATE_FORMAT()),因为返回的结果是服务端的时区,而不是connection的时区(对于JDBC来说就是JVM时区)。
CURRENT_TIMESTAMP(), CURRENT_TIME(), CURRENT_DATE()可以安全的使用,返回的结果会转换成connection时区(对于JDBC来说就是JVM时区)。
字符串类型
MySQL中字符串类型有以下几种:CHAR,VARCHAR,TEXT,ENUM和SET,此外还有BLOB。
类型 | 最大长度 | 说明 |
CHAR | 255字节 | CHAR是定长的,即在创建某字段时,如果指定长度为CHAR(4),则无论实际存储的字符是否有4这么长,MySQL都会分配4的空间 |
VARCHAR | 65535字节 | VARCHAR是变长的,即使指定长度为VARCHAR(16),如果实际存储的值只有8的长度,则MySQL实际存储时,也只会分配8的空间 |
TEXT | TINYTEXT / TEXT / MEDIUMTEXT / LONGTEXT | 创建索引时,必须指定长度;用于存储大文本,较少使用 |
BLOB | - | 以二进制形式(字节)存取,不必指定字符集,比如存储视频/图片等数据,但是一般不会使用 |
ENUM/SET | - | 枚举类型 |
使用建议
(1)在MySQL中,1个英文字母或1个数字占用1个字节,而1个汉字则根据不同的编码方式,会占用3或4个字节;
(2)在创建字符类型字段时,通过形如CAHR(n)或VARCHAR(n)指定的长度n,其含义为:该字段所能存储的字符的最大个数,而非最大字节数;这里的1各字符,可以是1个汉字,也可以1个字母,也可以是1个数字。如一个字段声明为VARCHAR(16),则该字段最多可以存储16个汉字或者16个字母或16个数字。
(3)如果存储的字符串长度几乎相等,使用char定长字符串类型。
(4)varchar是可变长字符串,不预先分配存储空间,长度不要超过5000,如果存储长度大于此值,定义字段类型为text,独立出来一张表,用主键来对应,避免影响其它字段索引效率。
(3)慎用ENUM
要么是数字,要么是字符串,要么是时间,ENUM里面是什么?ENUM更像业务数据的特征信息,不是数据类型(ENUM实际存储的是数字,而非字符串)
更改ENUM的代价大,不如使用TINYINT或者CHAR灵活,在海量数据下,假如后来发现ENUM需要增加一种枚举值,则需要ALTER TABLE,而使用TINYINT或者CHAR,则无需如此。
ENUM类型不是SQL标准,属于MySQL,而其他DBMS不一定有原生的支持。
参考
varchar(n)中的n和int(n)中的n到底是什么意思
8 Reasons Why MySQL's ENUM Data Type Is Evil
《阿里巴巴Java开发手册v1.2》
Last updated