MySQL必知必会——schema与数据类型优化

47 阅读4分钟

选择优化的数据类型

更小的通常更好:占内存、磁盘、cpu缓存更少,但是要够用。

简单的更好

避免使用null:设计索引的时候避免使用可以为null的列

timestamp需要datetime一半的空间,但是时间范围会小

1 整数类型

tinyint8、smallint16、mediumint24、int36、bigint64

unsigned不允许负值

整数类型计算用bigint

2 实数类型

带有小数部分的数字

decimal是存储类型,不支持直接计算,计算的时候会转换为double,可以指定小数点前后允许的最大位数。

float占4字节,double占8字节

上面讨论的都是存储类型,mysql用double类型进行计算

可以用bigint代替decimal,只需要乘相应的倍数。

3 字符串类型

varchar:可变字符,额外1-2字节记录长度,更新的时候会有碎片化的问题,如果页内空间不够myisam会把行拆成不同的片段存储,innodb会分裂页。

char:定长,会删除末尾的空格,用空格填充

Binary:存储二进制字节码,用\0字节填充

varbinary:存储二进制字节码

字节比较比字符比较简单,速度更快

给varchar分配更长的列不好,是因为mysql会分配固定的内存空间给要存储的值,所以这种情况下使用内存临时表进行排序或操作的时候会很不好,用磁盘临时表排序的时候也很糟糕。

Bolb:存储的是字节码

Text:存储的是字符,有字符集和排序规则

这俩类型视为一个对象,存储的时候如果值太大会用外部存储区域来存储,此时每个行内用1-4个字节存储一个指针来指向外部存储的区域,外部存储区域存储真实的值。

这俩排序不是对整个数据进行排序,而是对前面的max_sort_length字节进行排序

用到这俩类型的地方用substring(column,length)来转换成字符串类型,这样就可以使用临时内存表,要不然会使用隐式临时表,即磁盘临时表

extra为using temporary就是用了隐式临时表

ENUM枚举类型:会把每个值在列里映射为整数类型,把整数和数据对应表存在.frm文件里,按内部定义的整数进行排序,字符串列表是固定的。

在查找表的时候用整数主键避免采用基于字符串的值进行关联。

4 日期和时间类型

mysql储存的时间粒度最小为秒。

datetime从1001年到9999年,8个字节的存储空间

timestamp:1980.1.1-2038,4字节的存储空间

5 位数据类型

BIT,最大的长度是64位

6 选择标识符

整形很好,尽量少选emum和set

避免使用字符串,myisam对字符串类型通常压缩

避免随机函数生成的值,可能会在很大的空间里,使得insert语句变满:1、增加随机IO,可能会导致页分裂,产生聚簇索引碎片,导致缓存效果很差。

mysql scheme设计中的陷阱

列数不能太多

关联不能太多,单个查询最好在11个表内做关联

不能过度使用枚举

不一定使用null就是不好

范式与反范式

1 范式的优点和缺点

更新操作更快,重复数据更少,范式后的表更小,更容易放在内存中处理,可能更少的使用distinct和group by。

缺点是通常需要关联,可能使一些索引策略无效

2 反范式的优点和缺点

避免了关联,最坏的情况是全表扫描,这样也避免了随机IO

3 混用范式和反范式

缓存表和汇总表

1 物化视图

预先计算并存储在磁盘上的表

2 计数器表

加快alter table操作的速度

有两种技巧:1、是在一个不提供服务的机器上执行alter table操作,然后和提供服务的主库切换2、是根据要求创建一个跟原表无关系的新表,然后重命名和删表来交换这两个表。

1 只修改.frm文件

下面操作可以不用建新表:

1、移除一个列的AUTO_INCREMENT

2、增加、移除或更改ENUM和set常量。

过程如下:

1、创建一个有相同结构的空表,并修改

2、执行FLUSH TABLES WITH READ LOCK锁住

3、交换.frm文件

4、UNLOCK TABLES打开锁

2 快速创建MYISAM索引

对于非唯一索引,可以先删掉,然后增加新的列,然后再加上索引

可以用骇客的方法。