在生产环境中,数据库字符集因为各种原因需要升级,比如为了支持汉字,从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. 字符集GBK和UTF8的区别说明

    GBK就是在保存你的帖子的时候,一个汉字占用两个字节..外国人看会出现乱码,此为我中华为自己汉字编码而形成之解决方案. UTF8就是在保存你的帖子的时候,一个汉字占用3个字节..但是外国人看的话不会乱 ...

  2. mysql中gbk编码汉字和英文_MySQL字符集 GBK、GB2312、UTF8区别 解决 MYSQL中文乱码问题...

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

  3. 深入理解字符,字符集,gbk,utf8

    原创博客地址:深入理解字符,字符集,gbk,utf8 字符,字符集,字符编码概念 字节 1 字节(Byte)是计算机中数据存储的基本单元,一字节等于一个8位的比特,计算机中的所有数据,不论是保存在磁盘 ...

  4. iconv php gbk utf8,PHP通过iconv将字符串从GBK转换为UTF8字符集

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

  5. mysql utf8和gbk的区别_MySQL字符集 GBK、GB2312、UTF8区别

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

  6. mysql设置字符集gb2312_MySQL字符集 GBK、GB2312、UTF8區別 解決 MYSQL中文亂碼問題

    MySQL中涉及的幾個字符集 character-set-server/default-character-set:服務器字符集,默認情況下所采用的. character-set-database:數 ...

  7. mysql gbk_MySQL字符集 GBK、GB2312、UTF8区别 解决MYSQL中文乱码问题

    MySQL字符集 GBK.GB2312.UTF8区别 解决MYSQL中文乱码问题 更新时间:2012年08月27日 21:17:11   作者: MYSQL中文乱码问题原因有很多,脚本之家以前发布过很 ...

  8. GBK和UTF8什么区别

    GBK和UTF8什么区别 http://wshw1982.blog.163.com/blog/static/149293620126114239414/ GBK的文字编码是双字节来表示的,即不论中.英 ...

  9. gbk与utf-8的区别

    很多用户问GBK与UTF-8版本有什么区别,这边作了个整理如下: ***CMS的GBK版本与UTF-8版本功能是一样的.只不过编码方式不同. GBK的文字编码是双字节来表示的,即不论中.英文字符均使用 ...

最新文章

  1. win32: 查询滚动条相关信息的注意事项
  2. 减少过敏反应的生活细节
  3. linux调度全景指南
  4. PAT1007 素数对猜想 (20 分)
  5. linux添加和增大交换分区(swap)的方法
  6. 大规模分布式系统资源管理(二)
  7. 计算机cmd是什么 74,CMD是什么?
  8. Redis学习笔记001---Windows下安装Redis
  9. C++11 std::bind
  10. Delphi语言基础
  11. DVWA-SQL Injection
  12. 从这条博客开始转变!
  13. 淘宝数据分析实战篇(附源码)
  14. Nvivo使用步骤记录
  15. BZOJ3894:文理分科
  16. 电脑D盘格式化了怎么恢复
  17. 99.扩展.霍尔三维结构方法论 vs 切克兰德方法论
  18. MATLAB铁轨检测+异物识别
  19. 本周c++学习小结和心得
  20. 无痕偷看小黄片,全被监视吗?

热门文章

  1. C++如何使用puff()的示例
  2. VTK:Points之DensifyPoints
  3. Qt Linguist 开发人员 programmers
  4. C语言打印字符串的所有排列组合(附完整源码)
  5. c++使用Vigenere加解密文本的算法(附完整源码)
  6. C++使用kahn实现topological sort拓扑排序算法(附完整源码)
  7. QT绘制百分比条形图。
  8. c++内存,堆和栈的区别
  9. 有什么办法可以判断页面是静态还是动态?_网络营销——网络营销专员到底是教你如何选择网站页面制作...
  10. java重新初始化吗_Java中为何已经重新赋值的变量在输出后会初始化?