Unicode 的支持

Unicode 的支持

Unicode 标准包括来自基本多语言平面 (BMP) 的字符和位于 BMP 之外的补充字符。

概要

BMP 字符的特征

  • 它们的代码点值在0到65535之间 (或 U+0000 到 U+FFFF)
  • 它们可以使用8位,16位或24位 (1到3个字节) 以可变长度编码进行编码
  • 可以使用16位 (2个字节) 以固定长度对其进行编码
  • 它们足以应付主要语言中的几乎所有字符

BMP 之外的补充字符

  • 它们的代码点值在 U+10000 和 U+10FFFF 之间
  • Unicode 对补充字符的支持要求字符集的范围超出 BMP 字符,因此比 BMP 字符占用更多的空间 (每个字符最多4个字节)

UTF-8

  • 根据 RFC 3629 实现了用于对 Unicode 数据进行编码的 UTF-8 (具有8位单位的 Unicode 转换格式) 方法,该方法描述了从 1-4 个字节的编码序列。
  • UTF-8 的思想是使用不同长度的字节序列对各种 Unicode 字符进行编码
    • 基本的拉丁字母,数字和标点符号使用1个字节
    • 大多数欧洲和中东的脚本字母均以2个字节的顺序排列
    • 韩文,中文和日文使用3字节或4字节序列。

支持的 Unicode 字符集

常用字符集

  • utf8mb4 (4字节 UTF-8 Unicode 编码)
    • utf8mb4 是 utf8mb3 的超集
    • 特点
      • 支持 BMP 和补充字符
      • 每个多字节字符使用 1-4 个字节,最多需要4个字节
  • utf8mb3 (3字节 UTF-8 Unicode 编码)

    已弃用,计划删除。

    • 特点
      • 仅支持 BMP 字符 (不支持补充字符)
      • 每个多字节字符使用1-3个字节,最多需要3个字节
    • utf8 是 utf8mb3 的别名;字符限制是隐式的,而不是名称中的显式

    • MySQL 立即将语句中的 utf8mb3 实例转换为 utf8,所以用户使用以下语句查看时看到的是 utf8

      SHOW CREATE TABLE
      SELECT CHARACTER_SET_NAME FROM INFORMATION_SCHEMA.COLUMNS
      SELECT COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS
      
    • 除去 CHARACTER SET 子句,其他地方也可以用 utf8mb3
      mysqld --character-set-server=utf8mb3
      
      SET NAMES 'utf8mb3'; /* and other SET statements that have similar effect */
      SELECT _utf8mb3 'a';
      
  • utf8 (utf8mb3 的别名)

其他字符集

  • ucs2 (UCS-2 Unicode 编码)

    • 特点
      • 仅支持 BMP 字符 (不支持补充字符)
      • 使用固定长度的16位编码,每个字符需要2个字节
  • utf16 (UTF-16 Unicode 编码)
    • utf16 字符集是 ucs2 字符集加扩展名,可以对补充字符进行编码

    • 每个字符使用2或4个字节

    • 特点

      • 对于 BMP 字符,utf16 和 ucs2 具有相同的存储特征:相同的代码值,相同的编码,相同的长度。

      • 对于补充字符,utf16 具有一个特殊的序列,用于使用32位表示该字符。 这称为“代理”机制

        • 由于 utf16 支持代理,而 ucs2 不支持,因此存在仅在 utf16 中适用的有效性检查:您不能在没有底部代理的情况下插入顶部代理

        • 对于技术上有效但不是真正 Unicode 的字符 (即,Unicode 认为是“未分配的代码点”或“专用”字符,甚至是“非法”字符,如 0xffff ),没有有效性检查。

        • 因为 MySQL 必须允许最坏的情况 (一个字符需要四个字节) ,所以 utf16 列或索引的最大长度仅为 ucs2 列或索引的最大长度的一半

          CREATE TABLE tf (s1 VARCHAR(1536) CHARACTER SET ucs2) ENGINE=MEMORY;
          CREATE INDEX i ON tf (s1);
          CREATE TABLE tg (s1 VARCHAR(768) CHARACTER SET utf16) ENGINE=MEMORY;
          CREATE INDEX i ON tg (s1);
          
  • utf16le (UTF16-LE 编码)
    • 像 utf16一样,但是 little-endian 而不是 big-endian
    • 每个字符使用2或4个字节
  • utf32 (UTF-32 Unicode 编码)
    • utf32 占用的空间是 ucs2 的两倍,也比 utf16 占用更多空间,但是 utf32 与 ucs2 一样具有可预测的存储优势:utf32 所需的字节数等于字符数乘以4。而且,与 utf16 不同, utf32 中没有编码技巧,因此存储的值等于代码值
    • 每个字符使用4个字节

在3字节和4字节 Unicode 字符集之间转换

从 utf8mb3 转换为 utf8mb4 的一个优点是,应用程序可以使用补充字符。

utf8mb4 和 utf8mb3 区别

  • utf8mb3 仅支持 BMP。utf8mb4 在 BMP 基础上,还支持补充字符
  • utf8mb3 每个字符最多使用3个字节,utf8mb4 每个字符最多使用4个字节

就表内容而言,转换没有问题

  • 对于 BMP 字符,utf8mb4 和 utf8mb3 具有相同的存储特征:相同的代码值,编码,长度
  • 对于补充字符,utf8mb4 需要4个字节来存储它,而 utf8mb3 根本不能存储该字符。
    • 将 utf8mb3 列转换为 utf8mb4 时,不必担心转换辅助字符,因为没有辅助字符

就表结构而言,存在某些不兼容性

  • 对于可变长度字符数据类型 (VARCHAR 和 TEXT 类型),utf8mb4 列的字符允许的最大长度小于 utf8mb3 列的字符的最大允许长度

  • 对于所有字符数据类型 (CHAR,VARCHAR 和 TEXT 类型),utf8mb4 列可索引的最大字符数少于 utf8mb3 列

  • 因此,要将表从 utf8mb3 转换为 utf8mb4 ,可能需要更改某些列或索引定义

    • 转换前
      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;
      
    • 转换
      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 占3个字节,utf8mb4 占4个字节。对于 CHAR,VARCHAR 和 TEXT 数据类型需要注意
    • 检查 utf8mb3 列的所有定义,并确保它们不超过存储引擎的最大长度

    • 检查 utf8mb3 列上的所有索引,并确保它们不超过存储引擎的最大长度。有时,由于存储引擎的增强,最大值可能会更改

      • TINYTEXT 列最多可容纳255个字节,因此最多可容纳85个3字节或63个4字节字符。VARCHAR 是类似的

      • 对于使用 COMPACT 或 REDUNDANT 行格式的表,InnoDB 的最大索引长度为767字节,因此对于 utf8mb3 或 utf8mb4 列,您最多可以分别索引255个或191个字符

        col1 VARCHAR(500) CHARACTER SET utf8, INDEX (col1(255))
        col1 VARCHAR(500) CHARACTER SET utf8mb4, INDEX (col1(191))
        

回退需要考虑的因素

  • utf8mb3 和 ucs2 数据应该没有问题
  • 服务器必须具有足够的最新性,以识别引用所要转换的字符集的定义
  • 对于引用 utf8mb4 字符集的对象定义,可以在降级之前使用 mysqldump 转储它们,编辑转储文件以将 utf8mb4 的实例更改为 utf8,然后在较旧的服务器中重新加载该文件,只要不使用4字节字符

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注