### 10.9.8 3 字节和 4 字节 Unicode 字符集之间的转换

本节介绍了在`utf8mb3`和`utf8mb4`字符集。

笔记

这个讨论主要集中在之间的转换`utf8mb3`和`utf8mb4`, 但类似的原则适用于在`ucs2`字符集和字符集如`utf16`要么`utf32`.

这`utf8mb3`和`utf8mb4`字符集的区别如下：

-   `utf8mb3`仅支持基本多语言平面 (BMP) 中的字符。`utf8mb4`还支持位于 BMP 之外的补充字符。

-   `utf8mb3`每个字符最多使用三个字节。`utf8mb4`每个字符最多使用四个字节。

笔记

本次讨论是指`utf8mb3`和`utf8mb4`要明确引用 3 字节和 4 字节 UTF-8 字符集数据的字符集名称。例外是在表定义中，`utf8`使用，因为 MySQL 转换实例`utf8mb3`在此类定义中指定`utf8`，这是一个别名`utf8mb3`.

转换的优势之一`utf8mb3`到`utf8mb4`是这使应用程序能够使用补充字符。一种权衡是这可能会增加数据存储空间需求。

在表格内容方面，从`utf8mb3`到`utf8mb4`没有问题：

-   对于 BMP 字符，`utf8mb4`和`utf8mb3`具有相同的存储特性：相同的代码值、相同的编码、相同的长度。

-   对于一个补充字符，`utf8mb4`需要四个字节来存储它，而`utf8mb3`根本无法存储角色。转换时`utf8mb3`列到`utf8mb4`，您不必担心转换补充字符，因为没有。

    在表结构方面，这些是主要的潜在不兼容性：

-   对于可变长度字符数据类型 ([`VARCHAR`](char.html)和[`文本`](blob.html)类型），字符的最大允许长度小于`utf8mb4`列比`utf8mb3`列。

-   对于所有字符数据类型 ([`字符`](char.html),[`VARCHAR`](char.html), 和[`文本`](blob.html)types），可以索引的最大字符数更少`utf8mb4`列比`utf8mb3`列。

    因此，要将表从`utf8mb3`到`utf8mb4`，可能需要更改某些列或索引定义。

    表格可以从`utf8mb3`到`utf8mb4`通过使用[`更改表`](alter-table.html).假设一个表有这个定义：


```
CREATE TABLE t1 (
  col1 CHAR(10) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
  col2 CHAR(10) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL
) CHARACTER SET utf8;
```

以下语句转换`t1`使用`utf8mb4`：

```
ALTER TABLE t1
  DEFAULT CHARACTER SET utf8mb4,
  MODIFY col1 CHAR(10)
    CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
  MODIFY col2 CHAR(10)
    CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;
```

转换时的问题`utf8mb3`到`utf8mb4`是列或索引键的最大长度在以下方面没有变化*字节*.因此，它在以下方面更小*人物*因为一个字符的最大长度是四个字节而不是三个。为了[`字符`](char.html),[`VARCHAR`](char.html)， 和[`文本`](blob.html)数据类型，在转换 MySQL 表时注意这些问题：

-   检查所有定义`utf8mb3`列并确保它们不超过存储引擎的最大长度。

-   检查所有索引`utf8mb3`列并确保它们不超过存储引擎的最大长度。有时，由于存储引擎的增强，最大值可能会发生变化。

    如果上述条件适用，您必须减少列或索引的定义长度，或者继续使用`utf8mb3`而不是`utf8mb4`.

    以下是一些可能需要进行结构更改的示例：

-   一种[`小文本`](blob.html)列最多可以容纳 255 个字节，因此它最多可以容纳 85 个 3 字节或 63 个 4 字节字符。假设你有一个[`小文本`](blob.html)使用的列`utf8mb3`但必须能够包含超过 63 个字符。您无法将其转换为`utf8mb4`除非您还将数据类型更改为更长的类型，例如[`文本`](blob.html).

    同样，一个很长的[`VARCHAR`](char.html)列可能需要更改为较长的列之一[`文本`](blob.html)类型，如果你想从`utf8mb3`到`utf8mb4`.

-   `InnoDB`对于使用的表，最大索引长度为 767 字节`[紧凑](glossary.html#glos_compact_row_format)`要么`[冗余](glossary.html#glos_redundant_row_format)`行格式，所以对于`utf8mb3`要么`utf8mb4`列，您最多可以分别索引 255 或 191 个字符。如果您目前有`utf8mb3`索引长度超过 191 个字符的列，您必须索引较少数量的字符。

    在一个`InnoDB`使用的表`[紧凑](glossary.html#glos_compact_row_format)`要么`[冗余](glossary.html#glos_redundant_row_format)`行格式，这些列和索引定义是合法的：

    ```
    col1 VARCHAR(500) CHARACTER SET utf8, INDEX (col1(255))
    ```

    使用`utf8mb4`相反，索引必须更小：

    ```
    col1 VARCHAR(500) CHARACTER SET utf8mb4, INDEX (col1(191))
    ```

    笔记

    为了`InnoDB`使用的表`[压缩](glossary.html#glos_compressed_row_format)`要么`[动态](glossary.html#glos_dynamic_row_format)`行格式，[索引键前缀](glossary.html#glos_index_prefix)允许超过 767 个字节（最多 3072 个字节）。使用这些行格式创建的表允许您为最多 1024 或 768 个字符编制索引`utf8mb3`要么`utf8mb4`列，分别。有关相关信息，请参阅[第 15.22 节，“InnoDB 限制”](innodb-limits.html)， 和[动态行格式](innodb-row-format.html#innodb-row-format-dynamic).

    只有当您有很长的列或索引时，才最可能需要上述类型的更改。否则，您应该能够将您的表格从`utf8mb3`到`utf8mb4`没有问题，使用[`更改表`](alter-table.html)如前所述。

    以下项目总结了其他潜在的不兼容性：

-   `设置名称'utf8mb4'`导致使用 4 字节字符集作为连接字符集。只要服务器没有发送 4 字节字符，就应该没有问题。否则，期望每个字符最多接收三个字节的应用程序可能会出现问题。相反，希望发送 4 字节字符的应用程序必须确保服务器能够理解它们。

-   对于复制，如果要在源上使用支持补充字符的字符集，则所有副本也必须理解它们。

    此外，请记住一般原则，如果表在源和副本上具有不同的定义，这可能会导致意外结果。例如，最大索引键长度的差异使得使用它有风险`utf8mb3`在源和`utf8mb4`复制品上。

    如果您已转换为`utf8mb4`,`utf16`,`utf16le`， 要么`utf32`，然后决定转换回`utf8mb3`要么`ucs2`（例如，要降级到旧版本的 MySQL），这些注意事项适用：

-   `utf8mb3`和`ucs2`数据应该没有问题。

-   服务器必须足够新以识别引用您要转换的字符集的定义。

-   对于引用的对象定义`utf8mb4`字符集，你可以用[**mysql转储**](mysqldump.html)在降级之前，编辑转储文件以更改`utf8mb4`到`utf8`, 并在旧服务器中重新加载文件，只要数据中没有 4 字节字符。较旧的服务器看到`utf8`在转储文件对象定义中创建使用（3 字节）的新对象`utf8`字符集。
