登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
2025 Gitee 年度开源项目评选投票进行中,快为你的心仪项目助力!
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
3
Star
46
Fork
21
DreamCoders
/
CoderGuide
代码
Issues
1169
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
为什么不建议在 MySQL 中使用 UTF-8
待办的
#IAJL0A
陌生人
拥有者
创建于
2024-08-13 10:10
<p style="text-align: left;">“utf8”只支持每个字符最多三个字节,而真正的UTF-8是每个字符最多四个字节。</p><p style="text-align: left;">MySQL一直没有修复这个bug,他们在2010年发布了一个叫作“utf8mb4”的字符集,绕过了这个问题。</p><p style="text-align: left;">当然,他们并没有对新的字符集广而告之(可能是因为这个bug让他们觉得很尴尬),以致于现在网络上仍然在建议开发者使用“utf8”,但这些建议都是错误的。</p><p style="text-align: left;">MySQL的“utf8mb4”是真正的“UTF-8”。</p><p style="text-align: left;">MySQL的“utf8”是一种“专属的编码”,它能够编码的Unicode字符并不多。</p><p style="text-align: left;">我们都知道,计算机使用0和1来存储文本。比如字符“C”被存成“01000011”,那么计算机在显示这个字符时需要经过两个步骤:</p><p style="text-align: left;">1、 计算机读取“01000011”,得到数字67,因为67被编码成“01000011”。</p><p style="text-align: left;">2、 计算机在Unicode字符集中查找67,找到了“C”。</p><p style="text-align: left;">同样的</p><p style="text-align: left;">1、 我的电脑将“C”映射成Unicode字符集中的67。</p><p style="text-align: left;">2、 我的电脑将67编码成“01000011”,并发送给Web服务器。</p><p style="text-align: left;">几乎所有的网络应用都使用了Unicode字符集,因为没有理由使用其他字符集。</p><p style="text-align: left;">Unicode字符集包含了上百万个字符。最简单的编码是UTF-32,每个字符使用32位。这样做最简单,因为一直以来,计算机将32位视为数字,而计算机最在行的就是处理数字。但问题是,这样太浪费空间了</p><p style="text-align: left;">UTF-8可以节省空间,在UTF-8中,字符“C”只需要8位,一些不常用的字符,比如“”需要32位。其他的字符可能使用16位或24位。一篇类似本文这样的文章,如果使用UTF-8编码,占用的空间只有UTF-32的四分之一左右。</p><p style="text-align: left;">MySQL的“utf8”字符集与其他程序不兼容,它所谓的“”,可能真的是一坨……</p><p style="text-align: center;"><br></p><p style="text-align: center;"><span style="color: rgb(72, 179, 120);"><strong>MySQL简史</strong></span></p><p style="text-align: left;"><strong>为什么MySQL开发者会让“utf8”失效?</strong> 我们或许可以从提交日志中寻找答案。</p><p style="text-align: left;">MySQL从4.1版本开始支持UTF-8,也就是2003年,而今天使用的UTF-8标准(RFC 3629)是随后才出现的。</p><p style="text-align: left;">旧版的UTF-8标准(RFC 2279)最多支持每个字符6个字节。2002年3月28日,MySQL开发者在第一个MySQL 4.1预览版中使用了RFC 2279。MySQL数据库开发的 36 条军规,这个要记住。</p><p style="text-align: left;">同年9月,他们对MySQL源代码进行了一次调整:<strong>“UTF8现在最多只支持3个字节的序列”</strong> 。</p><p style="text-align: left;">是谁提交了这些代码?他为什么要这样做?这个问题不得而知。在迁移到Git后(MySQL最开始使用的是BitKeeper),MySQL代码库中的很多提交者的名字都丢失了。2003年9月的邮件列表中也找不到可以解释这一变更的线索。</p><p style="text-align: center;"><span style="color: rgb(72, 179, 120);"><strong>不过我可以试着猜测一下</strong></span></p><p style="text-align: left;">2002年,MySQL做出了一个决定:如果用户可以保证数据表的每一行都使用相同的字节数,那么MySQL就可以在性能方面来一个大提升。</p><p style="text-align: left;">为此,用户需要将文本列定义为“CHAR”,每个“CHAR”列总是拥有相同数量的字符。如果插入的字符少于定义的数量,MySQL就会在后面填充空格,如果插入的字符超过了定义的数量,后面超出部分会被截断。</p><p style="text-align: left;">MySQL开发者在最开始尝试UTF-8时使用了每个字符6个字节,CHAR(1)使用6个字节,CHAR(2)使用12个字节,并以此类推。</p><p style="text-align: left;">应该说,他们最初的行为才是正确的,可惜这一版本一直没有发布。但是文档上却这么写了,而且广为流传,所有了解UTF-8的人都认同文档里写的东西。</p><p style="text-align: left;"><strong>1、</strong> 使用CHAR定义列(在现在看来,CHAR已经是老古董了,但在那时,在MySQL中使用CHAR会更快,不过从2005年以后就不是这样子了)。</p><p style="text-align: left;"><strong>2、</strong> 将CHAR列的编码设置为“utf8”。</p><p style="text-align: left;">我的猜测是MySQL开发者本来想帮助那些希望在空间和速度上双赢的用户,但他们搞砸了“utf8”编码。</p><p style="text-align: left;">所以结果就是没有赢家。那些希望在空间和速度上双赢的用户,当他们在使用“utf8”的CHAR列时,实际上使用的空间比预期的更大,速度也比预期的慢。而想要正确性的用户,当他们使用“utf8”编码时,却无法保存像“”这样的字符。</p><p style="text-align: left;">在这个不合法的字符集发布了之后,MySQL就无法修复它,因为这样需要要求所有用户重新构建他们的数据库。<strong>最终,MySQL在2010年重新发布了“utf8mb4”来支持真正的UTF-8。</strong></p><p style="text-align: center;"><span style="color: rgb(72, 179, 120);"><strong>总结</strong></span></p><p style="text-align: left;"><span style="color: rgb(74, 74, 74); background-color: rgb(255, 255, 255); font-size: 16px;">如果你在使用MySQL或MariaDB,不要用</span><span style="color: rgb(74, 74, 74); background-color: rgb(255, 255, 255); font-size: 16px;"><strong>“utf8”编码,改用“utf8mb4”</strong></span><span style="color: rgb(74, 74, 74); background-color: rgb(255, 255, 255); font-size: 16px;"> 。</span></p>
<p style="text-align: left;">“utf8”只支持每个字符最多三个字节,而真正的UTF-8是每个字符最多四个字节。</p><p style="text-align: left;">MySQL一直没有修复这个bug,他们在2010年发布了一个叫作“utf8mb4”的字符集,绕过了这个问题。</p><p style="text-align: left;">当然,他们并没有对新的字符集广而告之(可能是因为这个bug让他们觉得很尴尬),以致于现在网络上仍然在建议开发者使用“utf8”,但这些建议都是错误的。</p><p style="text-align: left;">MySQL的“utf8mb4”是真正的“UTF-8”。</p><p style="text-align: left;">MySQL的“utf8”是一种“专属的编码”,它能够编码的Unicode字符并不多。</p><p style="text-align: left;">我们都知道,计算机使用0和1来存储文本。比如字符“C”被存成“01000011”,那么计算机在显示这个字符时需要经过两个步骤:</p><p style="text-align: left;">1、 计算机读取“01000011”,得到数字67,因为67被编码成“01000011”。</p><p style="text-align: left;">2、 计算机在Unicode字符集中查找67,找到了“C”。</p><p style="text-align: left;">同样的</p><p style="text-align: left;">1、 我的电脑将“C”映射成Unicode字符集中的67。</p><p style="text-align: left;">2、 我的电脑将67编码成“01000011”,并发送给Web服务器。</p><p style="text-align: left;">几乎所有的网络应用都使用了Unicode字符集,因为没有理由使用其他字符集。</p><p style="text-align: left;">Unicode字符集包含了上百万个字符。最简单的编码是UTF-32,每个字符使用32位。这样做最简单,因为一直以来,计算机将32位视为数字,而计算机最在行的就是处理数字。但问题是,这样太浪费空间了</p><p style="text-align: left;">UTF-8可以节省空间,在UTF-8中,字符“C”只需要8位,一些不常用的字符,比如“”需要32位。其他的字符可能使用16位或24位。一篇类似本文这样的文章,如果使用UTF-8编码,占用的空间只有UTF-32的四分之一左右。</p><p style="text-align: left;">MySQL的“utf8”字符集与其他程序不兼容,它所谓的“”,可能真的是一坨……</p><p style="text-align: center;"><br></p><p style="text-align: center;"><span style="color: rgb(72, 179, 120);"><strong>MySQL简史</strong></span></p><p style="text-align: left;"><strong>为什么MySQL开发者会让“utf8”失效?</strong> 我们或许可以从提交日志中寻找答案。</p><p style="text-align: left;">MySQL从4.1版本开始支持UTF-8,也就是2003年,而今天使用的UTF-8标准(RFC 3629)是随后才出现的。</p><p style="text-align: left;">旧版的UTF-8标准(RFC 2279)最多支持每个字符6个字节。2002年3月28日,MySQL开发者在第一个MySQL 4.1预览版中使用了RFC 2279。MySQL数据库开发的 36 条军规,这个要记住。</p><p style="text-align: left;">同年9月,他们对MySQL源代码进行了一次调整:<strong>“UTF8现在最多只支持3个字节的序列”</strong> 。</p><p style="text-align: left;">是谁提交了这些代码?他为什么要这样做?这个问题不得而知。在迁移到Git后(MySQL最开始使用的是BitKeeper),MySQL代码库中的很多提交者的名字都丢失了。2003年9月的邮件列表中也找不到可以解释这一变更的线索。</p><p style="text-align: center;"><span style="color: rgb(72, 179, 120);"><strong>不过我可以试着猜测一下</strong></span></p><p style="text-align: left;">2002年,MySQL做出了一个决定:如果用户可以保证数据表的每一行都使用相同的字节数,那么MySQL就可以在性能方面来一个大提升。</p><p style="text-align: left;">为此,用户需要将文本列定义为“CHAR”,每个“CHAR”列总是拥有相同数量的字符。如果插入的字符少于定义的数量,MySQL就会在后面填充空格,如果插入的字符超过了定义的数量,后面超出部分会被截断。</p><p style="text-align: left;">MySQL开发者在最开始尝试UTF-8时使用了每个字符6个字节,CHAR(1)使用6个字节,CHAR(2)使用12个字节,并以此类推。</p><p style="text-align: left;">应该说,他们最初的行为才是正确的,可惜这一版本一直没有发布。但是文档上却这么写了,而且广为流传,所有了解UTF-8的人都认同文档里写的东西。</p><p style="text-align: left;"><strong>1、</strong> 使用CHAR定义列(在现在看来,CHAR已经是老古董了,但在那时,在MySQL中使用CHAR会更快,不过从2005年以后就不是这样子了)。</p><p style="text-align: left;"><strong>2、</strong> 将CHAR列的编码设置为“utf8”。</p><p style="text-align: left;">我的猜测是MySQL开发者本来想帮助那些希望在空间和速度上双赢的用户,但他们搞砸了“utf8”编码。</p><p style="text-align: left;">所以结果就是没有赢家。那些希望在空间和速度上双赢的用户,当他们在使用“utf8”的CHAR列时,实际上使用的空间比预期的更大,速度也比预期的慢。而想要正确性的用户,当他们使用“utf8”编码时,却无法保存像“”这样的字符。</p><p style="text-align: left;">在这个不合法的字符集发布了之后,MySQL就无法修复它,因为这样需要要求所有用户重新构建他们的数据库。<strong>最终,MySQL在2010年重新发布了“utf8mb4”来支持真正的UTF-8。</strong></p><p style="text-align: center;"><span style="color: rgb(72, 179, 120);"><strong>总结</strong></span></p><p style="text-align: left;"><span style="color: rgb(74, 74, 74); background-color: rgb(255, 255, 255); font-size: 16px;">如果你在使用MySQL或MariaDB,不要用</span><span style="color: rgb(74, 74, 74); background-color: rgb(255, 255, 255); font-size: 16px;"><strong>“utf8”编码,改用“utf8mb4”</strong></span><span style="color: rgb(74, 74, 74); background-color: rgb(255, 255, 255); font-size: 16px;"> 。</span></p>
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
MySql
未设置
标签管理
里程碑
未关联里程碑
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
未关联
master
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
1
https://gitee.com/DreamCoders/CoderGuide.git
git@gitee.com:DreamCoders/CoderGuide.git
DreamCoders
CoderGuide
CoderGuide
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册