Mysql 数据类型选择

摘自 《高性能 Myql》 第三版

Mysql 支持的数据类型非常多,选择存储那种类型可参考以下原则

  • 更小的通常更好,更小的数据类型查找速度快占用空间少
  • 简单就好,比如使用 Mysql 自建类型存储时间日期,应该用整形存储 IP 地址而非字符串。
  • 尽量避免 NULL,NULL 列占用更多空间且不利于索引优化,除了时间日期这样不适合用 0 或者空字符串代替。

整数类型

列类型 | 存储空间(字节) | 取值范围(SIGN) | 取值范围(UNSIGN)

  • | - | - | -
    tinyint | 1 | -128 ~ 127 | 0 ~ 255
    smallint | 2 | -32768 ~ 32767 | 0 ~ 65535
    mediumnint | 3 | -2^23 ~ 2^23-1 | 0 ~ 2^24 -1
    int | 4 | -2^31 ~ 2^31-1 | 0 ~ 2^32-1
    bigint | 8 | -2^63 ~ 2^63-1 | 0 ~ 2^64-1

MySql 虽可指定整数宽度如 INT(10),但并不会限制值的合法范围。对于存储和计算来说,INT(1) 和 INT(20) 是相同的。

实数类型

列类型 存储空间(字节) 是否精确
FLOAT 4
DOUBLE 8
DECIMAL 每4字节存9位数字,小数点占一位

浮点数在计算机系统中很多情况下都无法精确表示,如 0.1 + 0.2 只能粗略表达为 0.30000000000000004,所以需要精确运算时,首先考虑规避浮点计算,如货币数字存储时可以先乘以相应倍数转化为整数再存入数据库。

若无法避免计算浮点时,欲精确计算可用 DECIMAL ,MySQL 5.0 和更高版本允许 DECIMAL 最多存 65 个数字。DECIMAL(a,b),其参数含义:a 指定指定小数点左边和右边可以存储的十进制数字的最大个数,最大精度38;b指定小数点右边可以存储的十进制数字的最大个数。小数位数必须是从 0 到 a之间的值。默认小数位数是 0。

字符串 varchar 和 char

列类型 含义 额外占用空间
char(n) 固定长度,最多255个字符 0
varchar(n) n < 255 可变长度,最多255个字符 1 byte overhead
varchar(n) n >= 255 可变长度,最多65535个字符 2 byte overhead
tinytext 可变长度,最多255个字符 1 byte overhead
text 可变长度,最多65535个字符 2 byte overhead

varchar类型用于存储可变长字符串,它只占用必要的存储空间。

varchar需要使用 1 或 2 个额外字节记录字符串的长度:如果字符串的最大长度小于 255 则只占用 1 个字节用于记录字符串长度,如果字符串的长度大于 255 则要占用 2 个字节用于记录字符串的长度。这就代表varchar的最大长度就是 65535。但是在实际中varchar列不能达到 65535 这么大,因为对 innodb 来说,65535 是一行中所有 varchar 列共享的长度。

下面的这些情况使用 varchar 类型是合适的:

  • 字符串的最大长度比平均长度大很多
  • 列的更新很少。这是因为行是变长的,在 update 时可能使行变的比原来更长。如果行占用的空间增长,并且在页内没有更多的空间可以存储,就需要存储引擎特别的处理。例如,Innodb 存储引擎需要分裂页使行放入页内。这会导致增加内存碎片,降低数据库性能。
  • 使用了像 UTF-8 这样复杂的字符集,因其每个字符使用了不同的字节数存储。

char 类型是定长的。它的最大宽度为 255。定义char(10),那么不论你存储的数据是否达到了10个字符,都要占去10个字符的空间

varchar 和 char 的宽度都是以字符为单位的。两种类型相比,char 类型会去掉字符串末尾的空格,而 varchar 类型不会。

VARCHAR(5) 和 VARCHAR(20) 存储 hello 的空间开销是一样的,那么使用更短的列有何优势?虽然存储开销相同,但被内存读取时,内存会分配此列设置宽度的空间,若内存开销过大不利于临时表排序,降低查询速度。

长文本 TEXT

存储很大的数据而设计的类型,存储引擎通常会做特殊的处理,当TEXT值特别大时,InnDB会使用专门的外部存储区域,此时每个值在行内需要1~4个字节存储一个指针,然后外部区域存储实际的值。

TEXT只能对此列最前 max_sort_length 字节而非整个字符串做排序,并且 MySQL 不能将 TEXT 全部字符进行索引。故此建立索引必须给出前缀索引长度。

时间日期类型

列类型 存储范围 存储占用空间(字节) 保存形式
DATETIME 1001年到9999年之间 8 YYYYMMDDHHMMSS 格式数字数据,保存值与时区无关
TIMESTAMP 1970~2038 4 即 UNIX 时间戳格式,显示的值与时区有关,慎用

故而时间日期最好选择 DATETIME,并在存入的时候传 UTC 时间戳。

结论

  • 时间日期最好选择 DATETIME,并在存入的时候传 UTC 时间戳。
  • IP 地址存 UNSIGN INT,使用内置函数 INET_ATON()INET_NTOA() 转化
  • MD5 戳适合用 CHAR(32) ,因为其定长,变更时不容易产生碎片。
  • 电话号码 使用 UNSIGN INT,因数字类型比对效率比字符串的高。
  • 一定是固定长度字符的用 char;变长的字符串使用 varchar。
  • 超过 255 字节的考虑用 varchar 或者 text;并尽量用 varchar,检索效率更高。
posted @ 2020-04-30 18:04  Ever-Lose  阅读(268)  评论(0)    收藏  举报