在生产环境中,数据库字符集因为各种原因需要升级,比如为了支持汉字,从latin1字符集升级到GBK,后面为了支持多个语言文字,需要将GBK升级到UTF8等。迁移过程网上有很多,我今天主要想讲下字符集转换后,可能对业务产生的影响,我以GBK转换到UTF8为例说明。主要有两点:

  1. 汉字在GBK编码中占2个字节,在UTF8编码中占3个字节,而mysql的索引要求总长度不超过767个字节,因此索引字符数会被缩短(383->255),特别的,对于唯一索引,要求索引字段长度小于256个字符。
  2. 编码转换后,导致字段排序发生变化。

这篇文章主要为了说明编码转换后,字段排序如何受影响,会结合mysql源代码给出原因和分析。首先看测试用例,假设cmp_t(GBK编码)和cmp_t2(UTF8编码)分别是迁移前后的表。

测试用例:

操作

cmp_t(GBK)

cmp_t2(UTF8)

1

GBK表:

select c1,hex(c1) from cmp_t;

UTF8表:

select c1,hex(c1) from cmp_t2;

+------+---------+

| c1   | hex(c1) |

+------+---------+

| 一  | D2BB

| 二  | B6FE

| 三  | C8FD

| a    | 61

| 1    | 31

+------+---------+

+------+---------+

| c1   | hex(c1) |

+------+---------+

| 一  | E4B880

| 二  | E4BA8C

| 三  | E4B889

| a    | 61

| 1    | 31

+------+---------+

2

GBK表:

select c1,hex(c1) from cmp_t where c1>’a’ order by c1;

UTF8表:

select c1,hex(c1) from cmp_t2 where c1>’a’ order by c1;

+------+---------+

| c1   | hex(c1) |

+------+---------+

| 二  | B6FE    |

| 三  | C8FD

| 一  | D2BB

+------+---------+

+------+---------+

| c1   | hex(c1) |

+------+---------+

| 一  | E4B880

| 三  | E4B889

| 二  | E4BA8C

+------+---------+

从上面操作返回的结果我们可以得到以下几点信息:

  1. 汉字在GBK编码中占2个字节,在UTF8编码中占3个字节
  2. 数字和英文字符在GBK和UTF8编码中都只占一个字节
  3. 汉字在UTF8编码和GBK编码不同,排序后顺序变化了。

原理分析:

Mysql利用sortcmp函数对字符串进行比较,对于GBK的字符串和UTF8的字符串分别采用接口my_strnncollsp_gbk和my_strnncollsp_utf8比较,这两个函数分别在ctype-gbk.c和ctype-utf8.c中实现,两个函数实现逻辑类似,只是各有自己一套比较大小的规则,下面我主要描述下my_strnncollsp_utf8的比较逻辑和比较大小的规则。

比较逻辑:

  1. 获取字符串的第一个字节
  2. 根据UTF8的编码规则(附1),确定字符由几个字节组成
  3. 根据一定的算法算出字符的加权值(附2),比较大小;若不符合UTF8编码规范,认为是乱码,采用二进制比较(附3)
  4. 跳过步骤2返回的字节数,比较下一个字符。

附1:【接口: my_utf8_uni】

根据UTF8编码规则,符合编码规范的字符占用1-6个字节。

取字符串第一个字节 s

if s<0x80

表示字符占1个字节

elif s<0xe0

表示字符占2个字节

elif s<0xf0

表示字符占3个字节

else s<0xf8

表示字符占4个字节

elif s<0xfc

表示字符占5个字节

elif s<0xfe

表示字符占6个字节

英文字符和数字字符编码兼容ASCII,编码值小于0x80,因此都只占1个字节;汉字的utf8编码的首字节都在[0xe0,0xf0]之间,所以占3个字节。

附2:utf8编码比较大小规则

value = ((s[0] & 0x0f) << 12)| ((s[1] ^ 0x80) << 6) | (s[2] ^ 0x80)

s[0],s[1],s[2]表示组成汉字的三个字节,对参与比较的汉子字符进行计算得到value1和value2,通过比较value1和value2的大小,判断字符大小。

附3:二进制比较【接口: bincmp】

memcmp函数比较,即逐字节比较。

因此,如果业务上面需要依赖汉字比较的场景,需要考虑字符集升级(GBK->UTF8)的风险,主要是索引或主键中包含字符串字段需要特别关注,如果字符串中确定只包含有数字和字符,则不会存在问题。

字符集GBK升级UTF8的更多相关文章

  1. MySQL字符集 GBK、GB2312、UTF8区别 解决 MYSQL中文乱码问题 收藏 MySQL中涉及的几个字符集

    MySQL中涉及的几个字符集 character-set-server/default-character-set:服务器字符集,默认情况下所采用的.character-set-database:数据 ...

  2. PHP通过iconv将字符串从GBK转换为UTF8字符集

    PHP通过iconv将字符串从GBK转换为UTF8字符集的方法,需要的朋友可以参考下. 1. iconv()介绍 iconv函数可以将一种已知的字符集文件转换成另一种已知的字符集文件.例如:从GB23 ...

  3. GB2312、GBK和UTF-8三种编码以及QT中文显示乱码问题

    1.GB2312.GBK和UTF-8三种编码的简要说明 GB2312.GBK和UTF-8都是一种字符编码,除此之外,还有好多字符编码.只是对于我们中国人的应用来说,用这三种编码 比较多.简单的说一下, ...

  4. ASCII、Unicode、GBK和UTF-8字符编码的区别联系(转载)

    ASCII.Unicode.GBK和UTF-8字符编码的区别联系 转载自:http://dengo.org/archives/901 很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同 ...

  5. 字符编码GB2312、GBK、UTF-8的区别

    本文来自:javaeye网站 UTF8是国际编码,它的通用性比较好,外国人也可以浏览论坛 GBK是国家编码,通用性比UTF8差,不过UTF8占用的数据库比GBK大~ 提示:如果您的网站客户群体主要是面 ...

  6. 网络编码 GB2312、GBK与UTF-8的区别

    GB2312.GBK与UTF-8的区别  这是一个异常经典的问题,有无数的新手站长每天都在百度这个问题,而我,作为一个“伪老手”站长,在明白这个这个问题的基础上,有必要详细的解答一下.  首先,我们要 ...

  7. 解决mysql中表字符集gbk,列字符集Latin1,python查询乱码问题

    最近在公司碰到一个异常蛋疼的情况,mysql数据库中,数据库和表的字符集都是'gbk',但是列的字符集却是'latin1',于是蛋疼的事情出现了. 无论我连接字符串的`charset`设置为`gbk` ...

  8. 【JAVA编码专题】JAVA字符编码系列一:Unicode,GBK,GB2312,UTF-8概念基础

    这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记录下来以便日后参考. 为了构成一个完整的对文字编码的认识和深入把握,以便处理在Java开发过程中遇到的各种问 ...

  9. 告别乱码,针对GBK、UTF-8两种编码的智能URL解码器的java实现(转)

    效果图 字符 字符是早于计算机而存在,从人类有文明那时起,人们就用一个个符号代表世间万象.如ABC,如“一.二.三”. 字符集 字符集是所有字符的集合. XXX字符集 给字符集中的每一个字符套上一个序 ...

随机推荐

  1. Scalaz(3)- 基础篇:函数概括化-Generalizing Functions

    Scalaz是个通用的函数式编程组件库.它提供的类型.函数组件都必须具有高度的概括性才能同时支持不同数据类型的操作.可以说,scalaz提供了一整套所有编程人员都需要的具有高度概括性的通用函数,它是通 ...

  2. jquery easyui 弹出消息框 (转载) jQuery EasyUI API 中文文档 - 消息框(Messager) http://www.cnblogs.com/hantianwei/archive/2012/03/19/2407113.html

    <html> <head> <!-- 导入easyui插件的js和css样式; --> <link rel="stylesheet" ty ...

  3. linux下搭建php的集成环境

    一个偶然的机会,在项目中需要搭建PHP的环境,由于PHP开发需要的东西比较多,像apache.mysql.PHP环境等,如果一个一个装很可能会有安装不全的问题,为此选择了安装集成环境,这里选择的是xa ...

  4. 值得 Web 开发人员学习的20个 jQuery 实例教程

    这篇文章挑选了20个优秀的 jQuery 实例教程,这些 jQuery 教程将帮助你把你的网站提升到一个更高的水平.其中,既有网站中常用功能的的解决方案,也有极具吸引力的亮点功能的实现方法,相信通过对 ...

  5. Apple Watch PSD 源文件【免费素材下载】

    Apple Watch 是苹果公司于2014年9月发布的一款智能手表.分为运动款.普通款和定制款三种,采用蓝宝石屏幕,有银色,金色,红色,绿色和白色等多种颜色可以选择.这里分享的是 Apple Wat ...

  6. Nibbler – 免费的网站测试和指标评分工具

    Nibbler 是一款免费的工具,用于测试网站的各个方面指标.输入任意网站的地址,Nibbler 会给你一份报告,列出网站的10个关键领域的分数,包括可访问性,用户体验,搜索引擎优化,社交媒体和技术等 ...

  7. 20个最新的照片 PS 技巧,提升摄影水平

    相信很多人都知道 Photoshop 在照片编辑方面的强大,所以几乎每张照片经过 PS 处理后都可以变成一个真正的杰作.这里分享的这组 Photoshop 教程可以帮助你学习到新的照片处理技术.你会发 ...

  8. [js开源组件开发]tip提示组件

    tip提示组件 常见的应用场景中,总是难免会遇到提示信息,比如显示不完全时需要鼠标移上去显示title,比如验证时的错误提示,比如操作按钮的辅助说明等,所以我独立出来了一个小的js组件,tip提示组件 ...

  9. smarty访问数组中的数据,如果是关联数组直接用点.

    $tpl=new Smarty();//新建一个smarty对象,我使用的是Smarty-3.1.6版本 1.设置smarty模板路径$tpl->setTemplateDir():默认情况下是t ...

  10. Fragment与FragmentActivity的关系

    前阵用viewpaper+fragment做滑动引导,查阅了下网上的资料,发现在有两种做法,一个是自建类直接继承Activity另一种是继承FragmentActivity,很是迷惑,在查了些goog ...