作者 | 付宗阳

杏仁后端工程师,一个全栈开发的自虐者。

前言

从 Mysql 数据库角度来说,谈到存储就一定离不开字符集,只不过在我们日常开发中统一的 utf8/utf8mb4 编码,使我们常常忽略了字符集的影响,本文仅从字符集的角度来谈谈对 InnoDB 的存储设计的一点影响,以及 Mysql 是怎么兼容各种字符集的。

过一下字符集

Unicode 作为现在通用的字符集,通常采用两个字节表示一个字符,带来的副作用就是,原本采用 ASCII 字符集只需要一个字节的,却变成了 2 个字节,造成了空间浪费,而 UTF-8 编码规则,将 Unicode 编码成 1~4 个字节,ASCII 字符集继续保持了 1 个字节空间,而中文编码成了三个字节,如下图。

对存储带来了什么影响

先说明下 Mysql 中存在两种字符集 utf8 和 utf8mb4,以下例子均以 Mysql 的 utf8(1~3个字节)为例。

采用 utf8 编码的确很不错,但是也带来了一个问题,例如我在 Mysql 中定义了一个定长字符类型 char(5):

name type length
title char 5

所谓定长字符类型代表我要给 title 分配 5 个字符大小的空间,可是 utf8 每个字符可能是 1~3 个字节,我该分配多少空间合适呢?

理论上为了兼容,最好应该采用 utf8 的最大 3 个字节进行分配,也就是 5*3 = 15 个字节的空间,这样我不管以后怎么修改这个字段的值,空间都能完美满足需求,但是如果此时存储的都是英文,比如 5 个 I,就会足足浪费 10 个字节的空间,如果这列以后都存英文,那么至少会浪费 2/3 的空间。

在 Mysql5.0 之前的行格式设计中,也就是 Redundant 行格式,char(5) 的确就如上面设计占用了 15 个字节空间,随着版本的迭代,后续出来的 Compact,Dynamic,Compressed 行格式都采用了另一种设计。

在对于 utf8 这类变长编码规则的 char 类型,采用同 varchar 类型一样的存储方式,就是在前面用一个或两个字节表示该列实际占用的字节数,对应到上图存储 5 个 I 的例子,就是 05(实际占用字节数)+5 个存储 I 的字节空间。

当然,更极端点,我只存储了一个 I,这时 char(5) 就会使用 utf8 的最小字节数 1*5(char定义的字符长度)的大小作为最小分配空间,空出的 4 个字节空间用空格字符填充,也就是说,对于 title 来说,至少会分配 5 个字节空间。

上面只是对列为 char(5) 的数据进行说明,在真实数据库表中,会存在多列 varchar 或 char 类型,由上可知变长编码规则的 char 也是按 varchar 处理的,所以这些列的实际占用字节数都会逆序存放在行格式首部,被称为变长字段长度列表,而每列的数据,则是顺序存放在列值中,如下图,至于变长字段长度列表和 Null 值列表为什么是逆序的,大家有兴趣可以去想想。

带来的更新问题

采用上面的设计,在大部分情况下能省下了很多空间,也提升了查询效率,但是也带来了另一个问题,那就是更新,用两个例子说明下:

将 title 从 1个 I 更新为 5 个 I

这个很好处理,因为 char(5) 最低会分配 5 个字节空间,更改为 5 个 I,不会产生任何影响,直接更新就好。

将 title 从 5 个 I 更改为 5 个我

5 个我 = 5 * 3 = 15 个字节空间,而实际记录只有 5 个字节空间,空间不足以支撑更新,这时候的更新只能将原数据的整行记录删除,然后再新分配合适空间供其使用,看似也没什么,但是这种删 + 增实际会对页产生很多变更,这么多变更又要保证它的事务性,也就是记录 redo , undo 日志,还是挺复杂和麻烦的。

Mysql的字符集转换机制

一个请求从客户端到 Mysql 服务器,再到表,再返回给客户端,中间是经过多层字符集转换的,主要包括下面4层:

转换配置 说明 例子
character_set_client 客户端请求所用字符集 utf8
character_set_connection 服务器将 character_set_client 转码为 character_set_connection gbk
表、列字符集 将 character_set_connection 转码为表、列定义的字符集,反之亦然 ascii
character_set_results 返回客户端字符集 utf8

假设我们查询 title 列,并且 Mysql 各种变量以及列字符集采用上面表格的例子,那么转换如下:

select title from title_demo where title = 'IIIIII'

当然,实际开发中,我们都会统一均采用 utf8 ,这样就有效避免了各层字符集转换带来的性能影响。

总结

随着 Mysql 性能的提升,其代码实现复杂度也显著提升,为了性能,对一种场景进行区分各种情况,再对各种情况进行不同的优化处理,已经不再陌生,所以面对这么多复杂的实现,从一个小的切入点,发现其乐趣,也是挺有意思的。

全文完


以下文章您可能也会感兴趣:

  • 聊聊Hystrix 命令执行流程

  • Mysql redo log 漫游

  • RabbitMQ 如何保证消息可靠性

  • 复杂业务状态的处理:从状态模式到 FSM

  • 简单聊聊 TCP 的可靠性

  • 延时队列:基于 Redis 的实现

  • 你真的懂 Builder 设计模式吗?论如何实现真正安全的 Builder 模式

  • Actor 模型及 Akka 简介

  • 从零搭建一个基于 lstio 的服务网格

  • 容器管理利器:Web Terminal 简介

我们正在招聘 Java 工程师,欢迎有兴趣的同学投递简历到 rd-hr@xingren.com 。

查一个字段中字符集超过30的列_Mysql 的字符集以及带来的一点存储影响相关推荐

  1. 查一个字段中字符集超过30的列_详细解读MySQL的30条军规

    一.基础规范 (1)必须使用InnoDB存储引擎 解读:支持事务.行级锁.并发性能更好.CPU及内存缓存页优化使得资源利用率更高 (2)必须使用UTF8字符集 解读:万国码,无需转码,无乱码风险,节省 ...

  2. mysql查询字段纯字母_解决MySQL之中一个字段中无法精准的查询多语言语言字母的问题...

    解决MySQL之中一个字段中无法精准的查询多语言语言字母的问题 解决MySQL之中一个字段中无法精准的查询多语言语言字母的问题 目录 1.使用场景 2.实现过程及展示结果 2.1.修改字段排序规则为u ...

  3. 将页面多个下拉框的值以字符串拼接方式存放至数据库一个字段中

     1,当页面中有多个值,传入Controller并以字符串拼接方式,以","隔开存放至数据库一个字段中,页面中多个<select name="off"&g ...

  4. 如果一个文件的大小超过了一张磁盘的大小,你该如何存储?

    转载 转自 极客时间 从零开始学大数据 李智慧 文章, 我学完了做了个笔记总结了一下 如果一个文件的大小超过了一张磁盘的大小,你该如何存储? 单机时代,主要的解决方案是RAID:分布式时代,主要解决方 ...

  5. 修改一个字段中的部分内容

    修改表 AC_MENU中的某一个字段的部分值,数据太多,一个个替换显得尤为费事,有这个语句,就省事儿多了: 以下是将字段"MENUACTION"中包含值"http://1 ...

  6. SQL将查询结果合并到一个字段中并使用,分割,不使用GROUP_CONCAT和FOR XML PATH(‘‘)与存储过程

    需求背景: 项目中使用一个字段保存了外键信息,多个外键用[,](逗号)分割,在进行查询的时候需要将这些关联的外键相关字段查询出来. 如我有一个班级表,表中保存了班级班主任信息,班主任可以是多个人,多个 ...

  7. 栈练习之Example005-检查一个程序中的花括号、方括号和圆括号是否配对

    Example005 题目 试编写一个算法,检查一个程序中的花括号.方括号和圆括号是否配对,若全部配对,则返回1,否则返回0.对于程序中出现的一对单引号或双引号内的字符不进行括号配对检查.39为单引号 ...

  8. mysql查一个表3到5行的数据类型_MySQL入门(三) 数据库表的查询操作【重要】

    序言 本节比较重要,对数据表数据进行查询操作,其中可能大家不熟悉的就对于INNER JOIN(内连接).LEFT JOIN(左连接).RIGHT JOIN(右连接)等一些复杂查询. 通过本节的学习,可 ...

  9. mysql 查询一个字段快还是一条记录快_mysql (优化)查询一条再筛选某个字段和直接查询该条的某个字段的效率比较...

    查询所有,10000次, $sql = "select * from mh_user where (username='333') and (password='xxx')"; 总 ...

最新文章

  1. JS数组遍历的几种方式
  2. Spring4.x新特性
  3. VS2010与QT的集成开发环境
  4. 用html语言制作古诗网页,唐诗宋词网页设计.docx
  5. C++模板Trait
  6. Python新闻网站项目-7.Django内容后台管理系统管理开发
  7. 【基础语法】C语言编写贪吃蛇游戏
  8. WPS使用格式刷复制样式之后重新排序
  9. qt报错:In included file: expected member name or ‘;‘ after declaration specifiers
  10. Linux上接收广播
  11. 3D 电影、全息显示这些技术如何骗过我们的眼睛?
  12. 特征重要性排序--Permutation Importance
  13. Maya:绑定—机械臂动画
  14. 无人驾驶与室内移动机器人对比思考
  15. 新浪微博、微信朋友圈、qq空间分享---qq空间分享
  16. 大话数据结构(一)数据结构相关概念
  17. Allegro DFM Ravel Rule工具使用指导书
  18. Vue2.x项目SPA的SEO解决方案(预渲染-Prerendering)
  19. 2023东北农业大学计算机考研信息汇总
  20. CSS3新选择器,盒子模型,过渡动画transition,2D转换transform

热门文章

  1. 不知风险 何谈 5G?
  2. CSDN学院全面改版啦!这次真的“搞大”了!
  3. “弃用 iOS 后,我的那些 Android 替代方案!”
  4. 提升源代码安全管控 从源头保护敏感数据
  5. 了解架构设计远远不够!一文拆解 Tomcat 高并发原理与性能调优
  6. 云原生的基石,一文读懂容器、Docker、Pod到底是什么!
  7. 计算机视觉 AI 工具集 OpenVINO™,是你心目中的深度学习框架 Top1 吗?
  8. 36 万美元套利!3 步骤揭秘黑客 DeFi 闪电贷全过程
  9. TensorFlow Lite 实现首次移植到 Arduino!
  10. 5G商用牌照近期发放;华为削减手机订单;苹果、亚马逊、Google遭调查 | 极客头条...