《高性能MySQL》第4章,读书笔记。
选择数据类型的原则
更小的通常更好
尽量使用可以正确存储数据的最小的数据类型,因为这样会占用更少的磁盘、内存、CPU。
简单就好
简单数据类型的操作需要更少的CPU周期。
尽量避免NULL
当列中包含NULL时,会使得索引、索引统计和值的比较变得复杂。可以添加
DEFAULT
避免NULL
。
整数类型
数据类型 | 字节数 | 带符号最小值 | 带符号最大值 | 不带符号最小值 | 不带符号最大值 |
---|---|---|---|---|---|
TINYINT |
1 | -128 | 127 | 0 | 255 |
SMALLINT |
2 | -32768 | 32767 | 0 | 65535 |
MEDIUMINT |
3 | -8388608 | 8388607 | 0 | 16777215 |
INT |
4 | -2147483648 | 2147483647 | 0 | 4294967295 |
BIGINT |
8 | -9223372036854775808 | 9223372036854775807 | 0 | 18446744073709551616 |
MySLQ
可以为整数类型指定宽度,例如INT(11)
,指定宽度对于值的范围没有影响。
INT(N),N表示的是显示宽度,不足的用0补足,超过的无视长度而直接显示整个数字,但这要整型设置了unsigned zerofill
才有效。
1 | create table int_width_test( |
实数类型
数据类型 | 字节数 | 备注 |
---|---|---|
float |
4 | 单精度浮点型 |
double |
8 | 双精度浮点型 |
对于float
、double
有一个比较大的问题就是精度丢失。
原因很简单,其实在MySQL
中对对于float
类型的数据,只分配了32位的存储空间,对于double
类型值分配了64位存储空间。当我们的数据转化为二进制时的存储空间大于32位或者64位,MySQL
会将我们存储的数据从高位到低位进行截断。也就是说,当我们存储的空间小于32位或者64位时,数据是准确的,但是当我们存储的数据位数较多时,会出现数据不准确的现象。
对于这个问题,我们可以使用decimal
的类型进行解决。
其实decimal
可以解决精度丢失的原因:
- 更大的存储空间
- 通过字符串化或者其他的方式特殊存储起来
想要深入了解这一方面的读者,可以看我的第二篇参考文献。
字符串类型
CHAR
和VARCHAR
类型
VARCHAR
类型存储可变长度字符串。
实现方式:需要额外的1或2个字节记录字符串的长度,如果长度小于或等于255字节,需要1字节记录。反之,需要2字节。
特点:节省空间,对于性能有帮助。但是需要注意的是,当行的长度变长时,需要进行额外的工作。
当行的长度变长时,
MyISAM
会将行拆成不同的片段存储,InnoDB
需要分裂页使行可以放入内存。
适用场景:字符串的最大长度比平均长度大很多;列的更新很少。
CHAR
类型存储定长字符串。
实现方式:MySQL
会根据定义分配空间,存储的时候会删除字符串的末尾空格。CHAR
值会根据需要采用空格进行填充以方便比较。
适用场景:很短的字符串,或所有值都接近一个长度。
BLOB
和TEXT
类型
BLOB
和TEXT
类型都是为存储很大的数据而设计的字符串数据类型。
BLOB
类型存储的是二进制数据,没有排序规则或字符集。
TEXT
类型存储的是字符串,有字符集和排序规则。
MySQL
把BLOB
和TEXT
当作独立的对象处理。当BLOB
和TEXT
值太大时,InnoDB
会使用专门的外部排序存储区域来存储,每个值在行内需要1~4个字节存储一个指针,在外部存储区域内存储实际的值。
当使用
BLOB
和TEXT
列,在遇到使用临时表的情况时,无法使用内存临时表,只能在磁盘上创建临时表。这样会造成严重的性能开销,所以,尽量避免使用BLOB
和TEXT
类型。
使用枚举(ENUM
)代替字符串类型
使用 MySQL ENUM
作为列的数据类型
好处:
- 使得数据更紧凑进而节省空间。
- 更好的可阅读性。
缺点:
MySQL
内部存储的是整数,如果使用数字作为ENUM
枚举常量,容易混乱。- 枚举字段按照内部存储的整数而不是定义的字符串进行排序。
- 枚举字段是固定的,添加或者删除字符串必须使用
ALTER TABLE
。
日期和时间
类型 | 字节 | 特征 |
---|---|---|
DATETIME |
8 | 与时区无关,时间范围:1000-01-01 00:00:00 to 9999-12-31 23:59:59 |
TIMESTAMP |
4 | 与时区有关,时间范围:1970-01-01 00::00:01 to 2038-01-19 03:14:07 |
通常推荐使用TIMESTAMP
,因为它比DATETIME
空间效率更高。