MySQL 优化数据大小

通过设计表结构来最小化磁盘空间占用,能够减少磁盘数据的读写,实现性能提升。较小的表通常需要更少的内存,这也意味着在查询时,表中数据能够被更快速地处理,表数据的缩减也会使得索引数据更小,索引查询更高效。

MySQL 支持不同的存储引擎和行格式,对于每一张表,都能为其设置合适的存储引擎和索引类型。应用选择合适的表格式能够提升整体性能。

通常优化表数据大小的方式如下:

  1. 表字段
  2. 行格式
  3. 索引
  4. JOINS
  5. 规范化(Normalization)

1. 表字段

在满足业务场景的条件下,尽量使用最高效,最小的字段类型。MySQL 有很多专门的数据类型来减少磁盘空间占用,比如尽可能使用更小的整数类型,mediumint 比 int 更好,因为它能节省 25% 的空间。

声明字段类型时,尽量使用 not null,它能够让 SQL 执行更快,因为这样能更好地使用索引,消除测试每个值是否为 null 的开销。避免为表中所有节点设置 null 作为默认值。

2. 行格式

InnoDB 表默认使用 DYNAMIC 行格式,通过配置 innodb_default_row_format 参数可以修改默认的行格式,也可以在建表或者改表指定 ROW_FORMAT 子句显式指定表的行格式。

行格式的 compact 家族,包括 COMPACT,DYNAMIC 和 COMPRESSED,能够减少行存储空间,但是会增加 CPU 的额外消耗。如果业务负载是典型的受缓存命中率和磁盘速度影响,那么小的存储空间其综合性能将会更高,如果业务负载受 CPU 速度影响,那么 compact 家族的格式可能会更慢一点。

compact 家族的行格式能够对变长字符的 CHAR 类型存储进行优化,比如 utf8mb3 或者 utf8mb4。当行格式设置为 REDUNDANT 时,CHAR(N) 占用 N*单个字符的最大长度。许多语言主要还是使用单字节的 utf8 字符,所以这种固定的存储长度就会浪费空间。如果使用 compact 家族的行格式,InnoDB 分配一个可变的存储空间,其长度为 N~N*单个字符的最大长度,最小存储长度为 N 字节,在典型场景下可以就地更新。

在创建表或者改表时,指定 ROW_FORMAT=compressed,能够进一步减少数据占用的空间。

对于 MyISAM 表,如果没有使用变长字段(varchar,text,blob),行格式将会变成固定大小,这种情况下执行速度会更快,但是会浪费存储空间。如果就是想要固定长度的行格式,即使有 varchar 类型的字段,也可以指定 ROW_FORMAT=FIXED 来声明使用固定长度的行格式。

3. 索引

表的主索引应该尽可能的短,这样可以更高效地定位每行记录。对于 InnoDB 表,二级索引会存储主键索引的值,所以如果有很多二级索引,短的主键索引将会节省大量的磁盘空间。

只创建能够提高查询效率的索引,索引能够加速查询,但是会减慢插入和更新操作。如果需要根据多个字段条件进行查询,应该创建一个联合索引,而不是每个字段上都创建一个单独的索引。联合索引的第一部分需要是最常用的字段,并且如果其包含大量重复值,将会有一个比较好的压缩效果。

如果一个长文本字段,其前缀字符已经有比较好的唯一性,那么对其创建前缀索引,效果更好,占用空间也更少,并且效率很高,索引小可以放在缓存中,减少磁盘 IO 消耗。

4. JOINS

在某些情况下,将一个经常被扫描的表拆分为两个是非常有用的,尤其它是一个动态格式表,可以使用一个较小的静态格式表用来查找相关行,提升效率。

在 join 连接的表中,字段类型应当完全相同,这样能够使 join 执行更快,避免不必要的类型转换。

保持字段名称简单,能够在不同的表中使用相同的字段名称,可以简化 join 查询语句。比如一个顾客表(customer),可以使用 name 代替 customer_name。另外为了和其他数据库兼容,字段名称应当小于 18 个字符。

5. 规范化(Normalization)

通常,尽量使所有数据不要冗余(参考数据库理论中称为第三范式的内容)。不要存储重复冗长的值,例如名称和地址,而是为它们分配唯一的 id,根据需要在多个较小的表中重复这些 id,并通过在 join 子句中引用 id 来连接查询中的表。

如果速度比磁盘空间和保留多个数据副本的维护成本更重要,例如在商业智能分析场景中,需要分析大表中的所有数据,可以放宽规范化限制,创建冗余数据或者创建摘要表(summary tables),以获得更高的速度。


本文译自:

https://dev.mysql.com/doc/refman/5.7/en/data-size.html

文章评论

0条评论