热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mysqlutf8utf8mb4_为什么mysql要额外加入一个utf8mb4数据类型,而不是原地升级utf8?...

MySQL为什么在这个地方犯2。以下内容仅仅为一种猜测。先说一下utf8的标准,早期是用1~6个byte来表示一个字符。所以最早的MySQL实现

MySQL为什么在这个地方犯2。以下内容仅仅为一种猜测。

先说一下utf8的标准,早期是用1~6个byte来表示一个字符。所以最早的MySQL实现,一个Char是用6个Bytes去实现的。这是正确的做法。但是MySQL为了性能,希望用户使用等长度的字符列。也就是说,一个字符如果用不到6个byte,存储里就会被填充空白符号。学过计算机的人都会明白等长字符,用数组的索引值去找到数据会非常快。早期的RFC2279规定一个UTF8字符被编码为1~6个byte。后来才改成了1~4个。

为此,MySQL甚至搞过一个“static-format“的存储结构,就是用定长数据来加速数据访问。(但这个东西只能用在MyISAM上,那时候MySQL还没收InnoDB)15.2.3.1 Static (Fixed-Length) Table Characteristics​dev.mysql.com

但也很容易看出来,这么干实在是太浪费空间了。绝大部分的英文用utf8编码1个byte就搞定了,中文等字符是3个byte。在1Charater = 6Byte的设计里,再加上2000年初时存储并不便宜,谁看了都会心疼。

好,基础讲完,再说历史。让我们回到2002年。MySQL计划在4.1版本支持utf8。4.1的早期开发版本用最多6个byte表示一个utf8字符,这是对的。但是MySQL不知道脑子里抽了哪根筋,在2002年9月27日,for no particular reason,搞出这么一个commit,强制让utf8编码只能处理最多3个byte的序列。

这个事情我查不到任何前因后果,查不到任何的文章,讨论和相关资料。

但大致猜测就是,MySQL当时又想用定长的存储,又觉得太浪费,干脆一鼓作气,把6改成了3。

在Unicode中,3个Byte可以支持所有的BMP(basic multi-lingual plane)的字符;但是无法支持SMP(supplementary multi-lingual plane),包括emoji(这是重灾区),一些生僻的CJK字符,一部分生僻的符号等。对于主要的文字(英文、欧洲各种语种、中文、日文……),3个byte的utf8也算是够用。

但是,多年之后,也许是苹果强力推emoji,大家才发现MySQL的utf8其实并不那么utf8。直到2010年,MySQL的5.5.3版本的时候,才引入了utf8mb4(从此刻开始,utf8是“utf8mb3“的alias)。这个change非常的不起眼,在更新总体介绍时压根就没提,只在明细里写了一行。也许是因为6改3这个变更实在太过于傻缺,不想张扬?

本题问为啥不把utf8原地升级,这个非常容易理解。大量的数据库文件已经按照了utf8的格式存储。如果“原地升级”也就意味着,所有已经存在的数据库文件都要重建。数据这个东西~都懂得。如果MySQL真的这么干了,估计就不是会被骂,而是会直接被判死刑。用utf8mb4的形式慢慢过渡也算是可以理解的做法。

顺便说一句。UTF8早期的标准RFC2279规定一个UTF8字符是1~6个Byte。这也是为什么早期Mysql把一个UTF8字符设计为6个Byte的原因。但是2003年11月,出了新的标准RFC3629,规定一个UTF8字符是1~4个Byte,就比MySQL做出那个很傻的commit晚了一年。历史真的很有趣。

从2002年到2019年,已经17年过去了,MySQL 8.0刚刚GA不久,但是utf8依然是utf8mb3的别名。不知道什么时候这个在一个莫名其妙的决策下诞生的奇行种才会被完全干掉。

哎~摘自MySQL8.0的文档



推荐阅读
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
  • 本文详细介绍了使用C#实现Word模版打印的方案。包括添加COM引用、新建Word操作类、开启Word进程、加载模版文件等步骤。通过该方案可以实现C#对Word文档的打印功能。 ... [详细]
  • PostgreSQL的upsert实例操作(insert
    建表语句:DROPTABLEIFEXISTSgoods;CREATETABLEgoods(store_cdint4NOTNULL,good_cdvarchar(50 ... [详细]
  • 带你把MySQL索引吃透了
    数据库|mysql教程mysql数据库-mysql教程支付宝网页支付源码,ubuntu脑图,tomcat显示默认主页,爬虫听书软件,php可以开发什么软件,天津关键词seo排名优化 ... [详细]
author-avatar
beng83790si
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有