在 mysql 中,永远不要使用“utf8”, 使用“utf8mb4”。-ag捕鱼王app官网

在 mysql 中,永远不要使用“utf8”, 使用“utf8mb4”。

作者:迹忆客 最近更新:2023/01/07 浏览次数:

今天的错误:我试图将 utf-8 字符串存储在 mariadb“utf8”编码的数据库中,rails 引发了一个奇怪的错误:

incorrect string value: ‘\xf0\x9f\x98\x83 <…’ for column ‘summary’ at row 1

这是一个 utf-8 客户端和一个 utf-8 服务器,位于具有 utf-8 排序规则的 utf-8 数据库中。 字符串😃 <...是有效的 utf-8

但问题是:mysql 的“utf8”不是 utf-8。

utf8”编码仅支持每个字符三个字节。 真正的 utf-8 编码——每个人都使用,包括你——每个字符最多需要四个字节。

mysql 开发人员从未修复此错误。 他们在 2010 年发布了一个解决方法:一个名为“utf8mb4”的新字符集。

当然,他们从来没有宣传过这个(可能是因为这个 bug 太尴尬了)。 现在,网络指南建议用户使用“utf8”。 所有这些指南都是错误的。

简而言之:

  • mysql 的“utf8mb4”表示“utf-8”。
  • mysql 的“utf8”意思是“专有字符编码”。 这种编码不能编码很多 unicode 字符。

我将在这里做一个笼统的声明:所有当前使用“utf8”的 mysql 和 mariadb 用户实际上应该使用“utf8mb4”。 任何人都不应该使用“utf8”。

什么是编码? 什么是 utf-8?

计算机将文本存储为 1 和 0。 这一段的第一个字母被存储为“01000011”,你的电脑画了“c”。 计算机分两步选择“c”:

  1. 你的计算机读取“01000011”并确定它是数字 67。那是因为 67 被编码为“01000011”。
  2. 你的计算机在 unicode 字符集中查找字符编号 67,发现 67 表示“c”。

当我输入“c”时,同样的事情发生在我这边:

  1. 我的计算机将“c”映射到 unicode 字符集中的 67
  2. 我的计算机编码为 67,向该 web 服务器发送“01000011”。

字符集是一个已解决的问题。 几乎 internet 上的每个程序都使用 unicode 字符集,因为没有动力去使用另一个。

但编码更像是一种判断。 unicode 有超过一百万个字符的插槽。 (“c”和“💩”是两个这样的字符。)最简单的编码 utf-32 使每个字符占用 32 位。 unicode 字符集和 utf-8、utf-16、utf-32 编码 这篇文章对几种编码进行了详细的介绍。 这很简单,因为计算机长期以来一直将 32 位组视为数字,而且它们非常擅长。 但它没有用:这是浪费空间。

utf-8 节省空间。 在 utf-8 中,像“c”这样的常见字符占用 8 位,而像“💩”这样的稀有字符占用 32 位。 其他字符占用 16 或 24 位。 像这样的博文在 utf-8 中占用的空间比在 utf-32 中少四倍。 所以它加载速度快四倍。

你可能没有意识到,但我们的计算机在幕后同意使用 utf-8。 如果他们没有,那么当我输入“💩”时,你会看到一堆乱七八糟的随机数据。

mysql 的“utf8”字符集与其他程序不一致。 当他们说“💩”时,它会犹豫。

一点 mysql 的历史

为什么 mysql 开发人员要使“utf8”无效? 我们可以通过查看提交日志来猜测。

mysql 从 4.1 版开始支持 utf-8。 那是 2003 年——在今天的 utf-8 标准 rfc 3629 出现之前。

以前的 utf-8 标准 rfc 2279 支持每个字符最多六个字节。 mysql 开发人员于 2002 年 3 月 28 日在 mysql 4.1 的第一个预发布版本中编写了 rfc 2279。

然后在 9 月份对 mysql 的源代码进行了一个神秘的单字节调整:“utf8 现在最多只能处理 3 个字节的序列。”

谁要求进行此更改? 为什么? 我不知道。 2003 年 9 月前后的邮件列表中没有任何内容可以解释这一变化。 (rfc 2279 于 2003 年 11 月宣布过时,为当前的 utf-8 标准 rfc 3629 让路。)

但是我可以猜到为什么 mysql 违反了标准。

早在 2002 年,如果用户可以保证表中的每一行都具有相同的字节数,mysql 就可以提高用户的速度。 为此,用户会将文本列声明为“char”。 “char”列中每条记录的值都具有相同数量的字符。 如果输入的字符太少,mysql 会在末尾添加空格; 如果你给它太多的字符,mysql 会截断最后的字符。

当 mysql 开发人员第一次尝试 utf-8 时,当时每个字符有 6 个字节,他们可能会犹豫:一个 char(1) 列需要 6 个字节; 一个 char(2) 列需要 12 个字节; 等等。

让我们明确一点:从未发布的初始行为是正确的。 它有据可查并被广泛采用,任何了解 utf-8 的人都会同意它是正确的。

但显然,mysql 开发人员(或用户或业务人员)担心一两个用户会做两件事:

  1. 选择 char 列。 (char 格式现在已经过时了。当时,使用 char 列的 mysql 速度更快。自 2005 年以来,情况就不是这样了。)
  2. 选择将这些 char 列编码为“utf8”。

我的猜测是 mysql 开发人员打破了他们的“utf8”编码来帮助这些用户: 1) 试图优化空间和速度的用户; 2)忽视了速度和空间的优化。

没有人赢。 想要速度和空间的用户使用“utf8”char 列仍然是错误的,因为这些列仍然比他们必须的更大和更慢。 而想要正确性的开发人员使用“utf8”是错误的,因为它不能存储“💩”。

一旦 mysql 发布了这个无效的字符集,它就永远无法修复它:这将迫使每个用户重建每个数据库。 mysql 终于在 2010 年发布了 utf-8 支持,但名称不同:“utf8mb4”。

为什么如此令人沮丧

显然这周我很沮丧。 我的 bug 很难找到,因为我被“utf8”这个名字骗了。 而且我不是唯一一个——我在网上找到的几乎所有文章都将“utf8”吹捧为 utf-8

名称“utf8”始终是一个错误。 这是一个专有字符集。 它创造了新的问题,并没有解决它想要解决的问题。

这是虚假宣传。


我的观点

  1. 数据库系统有细微的错误和怪癖,你可以通过避免使用数据库系统来避免很多错误。
  2. 如果你需要数据库,请不要使用 mysql 或 mariadb。 使用 postgresql。
  3. 如果你需要使用 mysql 或 mariadb,切勿使用“utf8”。 当你需要 utf-8 时,请始终使用“utf8mb4”。 立即转换数据库以避免以后出现麻烦。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

如何在 mysql 中声明和使用变量

发布时间:2024/03/26 浏览次数:115 分类:mysql

当你需要在 mysql 中的脚本中存储单个值时,最好的方法是使用变量。变量有不同的种类,有必要知道何时以及如何使用每种类型。

发布时间:2024/03/26 浏览次数:176 分类:mysql

本教程演示了如何在 mysql 中重置自动增量。

在 mysql 中实现刷新权限

发布时间:2024/03/26 浏览次数:211 分类:mysql

本教程介绍了 mysql 中的刷新权限命令,用于刷新授权表并影响允许的更改。

在 mysql 中设置时区

发布时间:2024/03/26 浏览次数:93 分类:mysql

在本教程中,我们将学习如何在 mysql 服务器中更改时区。

发布时间:2024/03/26 浏览次数:199 分类:mysql

本教程演示如何在 mysql 中转换为整数。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便
网站地图