Schema与数据类型优化
4.1 选择优化的数据类型
更小的通常更好
一般情况下,应该尽量使用可以正确存储数据的最小数据类型。
简单就好
简单数据类型的操作通常需要更少的CPU周期。
NULL
尽量避免通常情况下最好指定列为NOT NULL
,除非真的需要存储NULL值。
- 如果查询中的包含可以为NULL的列,对MySQL来说更难优化,因为可为NULL的列使得索引、索引统计和值比较都更复杂。
- 可为NULL的列会使用更多的存储空间,在MySQL里也需要特殊处理。
- 当可为NULL的列被索引时,每个索引记录需要一个额外的字节,在MyISAM里甚至还可能导致固定大小的索引变成可变大小的索引。
通常可以为NULL的列改成为NOT NULL带来的性能提升比较小,索引没有必要首先在现有schema中查找并修改掉这种情况,除非确定这回导致问题。但是如果计划在列上建索引,就应该尽量避免设计成可为NULL的列。
例外:InnoDB使用单独的位(bit)存储NULL值,索引对于稀疏数据有很好的空间效率,但这一点不适用与MyISAM。
4.1.1 整数类型
如果存储整数,可以使用这几种整数类型: TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT。分别使用8, 16, 24, 32, 64位存储空间。可以存储值得范围从-2N-1到2N-1-1,其中N是存储空间的位数。
MySQL可以为整数类型指定宽度,例如INT(11)
,对于大多数应用这是没有意义的:它不会限制值得合法范围,只是规定了MySQL的一些交互工具用来显示字符的个数。对于存储和计算来说,INT(1)和INT(20)是相同的。
4.1.2 实数类型
FLOAT和DOUBLE类型支持使用标准的浮点运算进行近似计算,DECIMAL类型用于存储精确的小数。浮点和DECIMAL类型都可以指定精度。 浮点类型在存储相同范围的值时,通常比DECIMAL使用更少的空间。 因为需要额外的空间和计算开销,所以应该尽量只在进行精确计算时才使用DECIMAL——例如存储财务数据。
4.1.3 字符串类型
VARCHAR和CHAR类型
很难精确的解释这些值是怎么存储在磁盘和内存中的,这跟存储引擎的具体实现有关。
VARCHAR
- VARCHAR类型用于存储可变长字符串,是最常见的字符串数据类型。它比定长类型更加节省空间。
- VARCAHR需要使用1或2个额外字节记录字符串的长度。
- VARCHAR节省了存储空间,所以对性能也有帮助。
下面这些情况使用VARCHAR是合适的:字符串列的最大长度比平局长度大很多;列的更新很少,所以碎片不是问题;使用了像UTF-8这样复杂的字符集,每个字符都使用不同的字节数进行存储。
CHAR
CHAR类型是定长的:MySQL总是根据定义的字符串长度分配足够的空间。CHAR很适合存储很短的字符串,或者所有值都接近同一个长度。例如存储MD5值。对于经常变更的数据,CHAR也比VARCHAR更好,因为定长的CHAR类型不容易昌盛碎皮,对于非常短的列,CHAR也比VARCHAR在存储空间上更有效率。
BLOB和TEXT类型
使用枚举ENUM代替字符串类型
4.1.4 日期和时间类型
DATETIME
这个类型能保存大范围的值,从1001年到9999年,精度为秒。它把日期和时间封装称格式为YYYYMMDDHHMMSS的整数中,与时区无关。使用了8个字节的存储空间。
TIMESTAMP
保存了从1970年1月1日午夜以来的秒数,它和UNIX时间戳相同,使用了4个字节的存储空间。
除了特殊行为以外,通常也尽量使用TIMESTAMP,因为它比DATETIME空间效率更高。
4.1.5 位数据类型
BIT
SET
4.2 MySQL schema设计中的陷阱
- 太多的列
- 太多的关联
- 全能的枚举
- 变相的枚举
- 非此发明的NULL