### 8.4.1 优化数据大小

[](<>)[](<>)[](<>)[](<>)[](<>)

设计您的表以最小化它们在磁盘上的空间。这可以通过减少写入磁盘和从磁盘读取的数据量来带来巨大的改进。较小的表通常需要较少的主内存，而它们的内容在查询执行期间被主动处理。表数据的任何空间减少也会导致可以更快处理的更小的索引。

MySQL 支持许多不同的存储引擎（表类型）和行格式。对于每个表，您可以决定使用哪种存储和索引方法。为您的应用程序选择合适的表格格式可以大大提高性能。看[第 15 章，*InnoDB 存储引擎*](innodb-storage-engine.html)， 和[第 16 章，*替代存储引擎*](storage-engines.html).

通过使用此处列出的技术，您可以获得更好的表性能并最小化存储空间：

-   [表格列](data-size.html#data-size-table-columns)

-   [行格式](data-size.html#data-size-row-format)

-   [索引](data-size.html#data-size-indexes)

-   [加入](data-size.html#data-size-joins)

-   [正常化](data-size.html#data-size-normalization)

#### 表格列

-   尽可能使用最有效（最小）的数据类型。MySQL 有许多专门的类型可以节省磁盘空间和内存。例如，尽可能使用较小的整数类型来获得较小的表。[`中型`](integer-types.html)通常是比[`INT`](integer-types.html)因为一个[`中型`](integer-types.html)列使用的空间减少了 25%。

-   将列声明为`非空`如果可能的话。通过更好地使用索引并消除测试每个值是否正确的开销，它使 SQL 操作更快`空值`.您还可以节省一些存储空间，每列一位。如果你真的需要`空值`表中的值，使用它们。只需避免允许的默认设置`空值`每列中的值。

#### 行格式

-   `InnoDB`表是使用`动态的`默认为行格式。使用除`动态的`， 配置[`innodb_default_row_format`](innodb-parameters.html#sysvar_innodb_default_row_format)，或指定`ROW_FORMAT`在 a 中明确选择[`创建表`](create-table.html)要么[`更改表`](alter-table.html)陈述。

    紧凑的行格式系列，包括`袖珍的`,`动态的`， 和`压缩`, 以增加某些操作的 CPU 使用为代价减少行存储空间。如果您的工作负载是典型的受缓存命中率和磁盘速度限制的工作负载，它可能会更快。如果是受 CPU 速度限制的罕见情况，它可能会更慢。

    紧凑的行格式系列还优化了[`字符`](char.html)使用可变长度字符集时的列存储，例如`utf8mb3`要么`utf8mb4`.和`ROW_FORMAT=冗余`,`字符（*`ñ`*)`占据*`ñ`*× 字符集的最大字节长度。许多语言可以主要使用单字节编写`utf8`字符，因此固定的存储长度通常会浪费空间。凭借紧凑的行格式系列，`InnoDB`在范围内分配可变数量的存储空间*`ñ`*到*`ñ`*× 通过去除尾随空格，这些列的字符集的最大字节长度。最小存储长度为*`ñ`*字节以促进典型情况下的就地更新。有关详细信息，请参阅[第 15.10 节，“InnoDB 行格式”](innodb-row-format.html).

-   要通过以压缩形式存储表数据来进一步最小化空间，请指定`ROW_FORMAT=压缩`创建时`InnoDB`表，或运行[**myisampack**](myisampack.html)对现有的命令`MyISAM`桌子。(`InnoDB`压缩表是可读可写的，而`MyISAM`压缩表是只读的。）

-   为了`MyISAM`表，如果您没有任何可变长度列 ([`VARCHAR`](char.html),[`文本`](blob.html)， 要么[`斑点`](blob.html)列），使用固定大小的行格式。这更快，但可能会浪费一些空间。看[第 16.2.3 节，“MyISAM 表存储格式”](myisam-table-formats.html).你可以暗示你想要固定长度的行，即使你有[`VARCHAR`](char.html)列与[`创建表`](create-table.html)选项`ROW_FORMAT=固定`.

#### 索引

-   表的主索引应该尽可能短。这使得识别每一行变得简单高效。对于`InnoDB`在表中，主键列在每个次索引项中都是重复的，因此，如果有许多次索引，则短主键可以节省大量空间。

-   只创建提高查询性能所需的索引。索引有利于检索，但会降低插入和更新操作的速度。如果主要通过搜索列的组合来访问表，请在这些列上创建一个复合索引，而不是为每一列创建单独的索引。索引的第一部分应该是使用最多的列。如果你*总是*使用多个列从表中进行选择时，索引中的第一列应该是重复次数最多的列，以便更好地压缩索引。

-   如果一个长字符串列很可能在第一个字符数上有一个唯一的前缀，那么最好只索引这个前缀，使用MySQL支持在列的最左边创建索引（参见[第13.1.15节，“创建索引语句”](create-index.html))。索引越短，速度越快，这不仅是因为它们需要的磁盘空间越少，还因为它们在索引缓存中提供的命中率越高，因此磁盘搜索次数也越少。看见[第5.1.1节，“配置服务器”](server-configuration.html).

#### 加入

-   在某些情况下，将一张经常扫描的表格分成两部分可能是有益的。如果它是一个动态格式表，并且可以使用较小的静态格式表，在扫描该表时可以使用该表来查找相关行，则尤其如此。

-   在具有相同数据类型的不同表中声明具有相同信息的列，以加速基于相应列的联接。

-   保持列名简单，以便可以在不同的表中使用相同的名称，并简化联接查询。例如，在名为`顾客`，使用列名称`名称`而不是`客户名称`为了使您的名称可移植到其他SQL Server，请考虑保持它们短于18个字符。

#### 规范化

-   通常情况下，尽量保持所有数据的非冗余性（观察数据库理论中所谓的第三范式）。不要重复名称和地址等冗长的值，而是为它们分配唯一的ID，根据需要在多个较小的表中重复这些ID，并通过引用join子句中的ID在查询中连接表。

-   如果速度比磁盘空间和保存多个数据副本的维护成本更重要，例如在分析大型表中所有数据的商业智能场景中，可以放松规范化规则、复制信息或创建摘要表以获得更高的速度。
