MySQL优化:数据类型

前言

MySQL(5.6)的数据类型非常多,大致可以分为四大类:numeric types(数值类型)date and time types(日期和时间类型)string (character and byte) types(字符串/字符/字节类型)spatial types(空间类型)

四大类共有32种,如何选取合适的数据类型,也是一个非常重要的问题。当表中数据量比较小的时候,不能凸显数据类型的重要性,一旦数据量大了之后,不合适的数据类型会带来非常大的麻烦。

本篇主要讲解数值类型日期时间类型字符串类型三种。

numeric types

numeric types(数值类型)又可以分为整数定点数浮点数,对应的类型分别如下

整数

对于整数数据类型,都可以表示成type[(M)] [UNSIGNED] [ZEROFILL]的形式,M表示最大显示宽度。最大显示宽度为255。显示宽度与类型可以存储的值的范围无关

UNSIGNEDZEROFILL是两个额外的属性,分别表示:是否有符号是否填充0

对于浮点定点数据类型,M是可以存储的总位数。 如果为数字列指定ZEROFILL,MySQL会自动将UNSIGNED属性添加到该列。

数据类型 大小 范围 解释
tinyint 1 byte 有符号类型范围:[-128, 127]
无符号类型范围:[0, 255]
非常小的整数
smallint 2 byte 有符号类型范围:[-32768, 32767]
无符号类型范围:[0, 65535]
小整数值
mediumint 3 byte 有符号类型范围:[-8388608, 8388607]
无符号类型范围:[0, 16777215]
中等整数值
int / integer 4 byte 有符号类型范围:[-2147483648, 2147483647]
无符号类型范围:[0, 4294967295]
整数值
bigint 8 byte 有符号类型范围:[-9223372036854775808, 9223372036854775807]
无符号类型范围:[0, 18446744073709551615]
极大整数值

定点数

对于定点数据类型,都可以表示成type[(M[, D])] [UNSIGNED] [ZEROFILL]的形式,看起来有点绕,实际上是存在三种写法:typetype(M)type(M, D)。其中M是可以存储的总位数,D是小数点后的位数(小数位数)。小数点和(对于负数)符号不计入M。如果D为0,则值没有小数点或小数部分。

数据类型 解释
decimal / dec / numeric / fixed decimal的最大位数(M)为65。支持的小数位数(D)的最大值为30。
如果省略D,则默认值为0。如果省略M,则默认值为10。
使用decimal列的所有基本计算(+,-,*,/)均以65位精度完成。
fixed可用于与其他数据库系统兼容。

浮点数

浮点数包括floatdouble两种类型

数据类型 解释
float[(M,D)] 单精度浮点数。M是总位数,D是小数点后的位数。如果省略MD,则将值存储到硬件允许的极限。单精度浮点数的精度约为小数点后7位
FLOAT(M,D)是非标准的MySQL扩展
float(p) 浮点数。 p表示位精度,但是MySQL仅使用此值来确定对结果数据类型使用FLOAT还是DOUBLE。如果p从0到24,则数据类型为FLOAT,没有MD值。如果p为25到53,则数据类型将变为DOUBLE,且没有MD值。
FLOAT(p)语法以实现ODBC兼容性
double[(M,D)] / double precision[(M,D)] / real[(M,D)] 双精度浮点数。M是总位数,D是小数点后的位数。如果省略MD,则将值存储到硬件允许的极限。双精度浮点数精确到大约15个小数位
DOUBLE(M,D)是非标准的MySQL扩展
如果启用REAL_AS_FLOAT SQL模式,则REALFLOAT的同义词,而不是DOUBLE

date and time types

用于表示时间值的日期和时间数据类型为DATETIMEDATETIMETIMESTAMPYEAR

类型 解释 零值
date 日期类型,支持的范围:[‘1000-01-01’, ‘9999-12-31’]
MySQL以YYYY-MM-DD格式显示date值,但允许使用字符串或数字将值分配给date
'0000-00-00'
datetime[(fsp)] 日期和时间组合,支持的范围:[‘1000-01-01 00:00:00.000000’, ‘9999-12-31 23:59:59.999999’]
MySQL以YYYY-MM-DD hh:mm:ss[.fraction]的格式显示datetime值,但允许使用字符串或数字将值分配给datetime
fsp表示小数位数,范围:[0, 6],如果不指定,默认为0,表示没有小数
支持自动初始化和更新
'0000-00-00 00:00:00'
timestamp[(fsp)] 时间戳类型,支持范围:('1970-01-01 00:00:01.000000’UTC, '2038-01-19 03:14:07.999999’UTC]
fsp表示小数位数,范围:[0, 6],如果不指定,默认为0,表示没有小数
'0000-00-00 00:00:00'
time[(fsp)] 时间类型,支持范围:[’-838:59:59.000000’, ‘838:59:59.000000’]
MySQL以hh:mm:ss[.fraction]的格式显示time值,但允许使用字符串或数字将值分配给time
fsp表示小数位数,范围:[0, 6],如果不指定,默认为0,表示没有小数
'00:00:00'
year[(2|4)] 2位或4位格式的年份。默认值为4位数字格式。 YEAR(2)或YEAR(4)的显示格式不同,但是值的范围相同。
在4位数格式中,值显示为:[1901, 2155],或者0000。
在2位数格式中,值显示为70至69,代表从1970到2069的年份。70-99表示1970-1999;00-69表示2000-2069
MySQL以YYYYYY格式显示YEAR值,但允许分配使用字符串或数字将值添加到YEAR列。
0000

对于timestamp类型,服务器处理timestamp定义的方式取决于explicit_defaults_for_timestamp系统变量的值。

  • 如果启用了explicit_defaults_for_timestamp,则不会将DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP属性自动分配给任何TIMESTAMP列。它们必须明确包含在列定义中。另外,任何未明确声明为NOT NULLTIMESTAMP都允许NULL值。
  • 如果禁用explicit_defaults_for_timestamp,则服务器按以下方式处理TIMESTAMP
    • 没有特别指定的情况下,insertupdate操作时,表中的第一个timestamp的值会被自动更新成当前时间(如果没有指定值,或者指定NULL),其他timestamp列如果设置了NOT NULL,而传入NULL时,也会被更新成当前时间
    • 可以使用DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP列定义子句来指定自动初始化和更新到当前日期和时间。默认情况下,第一个TIMESTAMP列具有这些属性。但是,可以将表中的任何TIMESTAMP列定义为具有这些属性。

从MySQL 5.6.6开始,explicit_defaults_for_timestamp可用。在5.6.6之前,服务器将处理TIMESTAMP,如禁用explicit_defaults_for_timestamp情况所述。

查看explicit_defaults_for_timestamp是否启用

show variables like 'explicit_defaults_for_timestamp';

string (character and byte) types

用于表示字符串(字符和字节)类型的数据类型有: CHARVARCHARBINARYVARBINARYBLOBTEXTENUMSET。.

对于字符串列CHARVARCHARTEXT类型)的定义,MySQL以字符单位解释长度规范。对于二进制字符串列BINARYVARBINARYBLOB类型)的定义,MySQL以字节单位解释长度规范

  • [NATIONAL] CHAR[(M)]
    • 固定长度的字符串,在存储时总是用空格填充到指定的长度。 M代表以字符为单位的列长M的范围是0到255。如果省略M,则长度是1
    • 除非启用了PAD_CHAR_TO_FULL_LENGTH SQL模式,否则在检索CHAR值时将删除尾部空格
    • NATIONAL CHAR(或其等效的简短格式NCHAR)是定义CHAR列应使用一些预定义字符集的标准SQL方法。 MySQL使用utf8作为此预定义字符集
  • [NATIONAL] VARCHAR(M)
    • 可变长度的字符串。 M表示最大列长度,以字符为单位M的范围是0到65535
    • VARCHAR的有效最大长度取决于最大行大小(65535字节,这个值在所有列之间共享)和所使用的字符集。例如,utf8字符每个字符最多需要三个字节,因此使用utf8字符集的VARCHAR列可以声明为最多21844个字符
    • MySQL存储varchar类型的数据时,需要1个字节或者2个字节作为数据的前缀,如果值的长度不超过255个字节,使用1个字节,如果有可能超过255个字节,则使用2个字节
    • MySQL不会从VARCHAR值中删除尾部空格
    • NATIONAL VARCHAR是定义VARCHAR列应使用某些预定义字符集的标准SQL方法。 MySQL使用utf8作为此预定义字符集。NVARCHARNATIONAL VARCHAR的简写

最佳实践

数值类型

  • 应该尽量使用可以正确存储数据的最小数据类型,更小的数据类型通常更快,因为它们占用更少的磁盘、内存和CPU缓存,并且处理时需要的CPU周期更少,但是要确保没有低估需要存储的值的范围,如果无法确认哪个数据类型,就选择你认为不会超过范围的最小类型
  • 尽量使用简单的数据类型,简单数据类型的操作通常需要更少的CPU周期,例如,
    • 整型比字符操作代价更低,因为字符集和校对规则是字符比较比整型比较更复杂,
    • 使用mysql自建类型,而不是字符串来存储日期和时间
    • 可以考虑用整型存储IP地址

日期和时间类型

日期类型的选取,最麻烦的地方在于datetimetimestamp这两个类型的选取。所以必须完全了解这两种类型的区别,再结合实际情况进行取舍。
datetimetimestamp区别

  • 存储: datetime占8个字节,timestamp占4个字节
  • 范围:datetime表示区间[1000-01-01 00:00:00, 9999-12-31 23:59:59],timestamp表示区间[1970-01-01 , 2038-01-19]
  • 时区:datetime值不随时区变化而变化,timestamp一旦时区变动,会自动修改timestamp的值
  • 效率:timestamp更轻量,索引起来更快

了解了这几点区别之后,相信比较容易就能做出取舍了。

字符串类型

字符串类型的选取,基本上也就纠结于charvarchar,所以需要了解两者的具体区别

  • 长度:char最长255个字符varchar最长约21844个字符
  • 检索:char检索时会自动去除尾部空格,varchar不会
  • 效率:char写效率比varchar高,以空间换时间

参考

  • https://dev.mysql.com/doc/refman/5.6/en/data-types.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章