MySQL字符集和比较规则
MySQL字符集和比较规则
字符集和比较规则简介
字符集: 描述字符与二进制数据的映射关系
比较规则:比较指定字符集中的字符的规则
字符集
我们知道,计算机无法直接存储字符串,实际存储的都是二进制数据。字符集是有限的,也就是字符范围,比如ASCII字符集包含了128个字符与进制数据的映射关系。将字符根据编码规则映射成二进制数据的过程叫做编码,将二进制数据根据编码规则映射到字符的过程叫做解码。
举个例子,在ASCII字符集中,存在如下映射关系:
'A' -> 01000001(十六进制为0x41)
'B' -> 01000010(十六进制为0x42)
'a' -> 01100001(十六进制为0x61)
'b' -> 01100010(十六进制为0x62)
'我' -> 不存在,因为ASCII字符集的字符范围里并不存在'我'与8位组的对应关系
查看字符集
命令:SHOW (CHARSET | CHARACTER SET) [LIKE 匹配的模式]
mysql> SHOW CHARSET;
+----------+---------------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+---------------------------------+---------------------+--------+
| ascii | US ASCII | ascii_general_ci | 1 |
| latin1 | cp1252 West European | latin1_swedish_ci | 1 |
| utf16 | UTF-16 Unicode | utf16_general_ci | 4 |
...
| utf32 | UTF-32 Unicode | utf32_general_ci | 4 |
| utf8mb3 | UTF-8 Unicode | utf8mb3_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 |
+----------+---------------------------------+---------------------+--------+
41 rows in set (0.01 sec)
本文使用的MySQL8.0版本中共支持41中字符集(仅列出了常用字符集)。其中Default collation为该字符集默认的比较规则,Maxlen是最多需要使用几个字节来映射一个字符。
比较规则
在确定字符集之后,还需要比较字符集中两个字符的大小或是否相等,此时,就需要用到字符集的比较规则。最简单的比较规则就是:直接比较两个字符对应的二进制编码的大小。一个字符集可以有多种比较规则。
查看比较规则
命令:SHOW COLLATION [LIKE 匹配的模式]
mysql> SHOW COLLATION LIKE '%utf8mb4%';
+----------------------------+---------+-----+---------+----------+---------+---------------+
| Collation | Charset | Id | Default | Compiled | Sortlen | Pad_attribute |
+----------------------------+---------+-----+---------+----------+---------+---------------+
| utf8mb4_0900_ai_ci | utf8mb4 | 255 | Yes | Yes | 0 | NO PAD |
| utf8mb4_0900_as_ci | utf8mb4 | 305 | | Yes | 0 | NO PAD |
| utf8mb4_0900_as_cs | utf8mb4 | 278 | | Yes | 0 | NO PAD |
| utf8mb4_0900_bin | utf8mb4 | 309 | | Yes | 1 | NO PAD |
...
| utf8mb4_general_ci | utf8mb4 | 45 | | Yes | 1 | PAD SPACE |
...
| utf8mb4_spanish_ci | utf8mb4 | 231 | | Yes | 8 | PAD SPACE |
| utf8mb4_zh_0900_as_cs | utf8mb4 | 308 | | Yes | 0 | NO PAD |
+----------------------------+---------+-----+---------+----------+---------+---------------+
89 rows in set (0.00 sec)
上述代码块中展示了MySQL8.0中utf8mb4这个字符集的常用比较规则。这些比较规则是有规律的。
- 比较规则的名称以其关联的字符集名称开头。
- 后面紧跟着该比较规则所应用的语言,比如utf8mb4_spanish_ci表示西班牙语的比较规则。utf8mb4_general_ci是一种通用的比较规则。
- 名称后缀表示该规则是否区分大小写、语言中的重音等。具体后缀如下表所示
| 后缀 | 英文释义 | 描述 |
|---|---|---|
| _ai | accent insensitive | 不区分重音 |
| _as | accent sensitive | 区分重音 |
| _ci | case insensitive | 不区分大小写 |
| _cs | case sensitive | 区分大小写 |
| _bin | binary | 以二进制方式比较 |
常用的字符集
计算机是美国人发明的,因此ACISS字符集中包含了26个英文字母和一些字符就足够美国人日常使用了。但是如果一些其他国家和地区想要使用计算机,就必须有一套包含自身语言的字符集,比如GBK、IOS-8859-1等字符集。以下是一些常用的字符集:
ASCII:包含128个字符,包括空格、标点符号、数字、大小写字母和一些不可见字符(回车、制表符等)。由于ASCII字符集总共才128个字符,所以使用**一个字节(8位)**就足够保存了。GB2312:收录6763个汉字以及拉丁字母、希腊字母等,兼容ASCII字符集。使用GB2312编码时,如果该字符存在于ASCII字符集中,则使用一字节编码,否则采用两字节编码。这种使用不同不同字节数来表示一个字符的编码方式称为变长编码。GBK(国标扩展的首字母):GBK对GB2312进行了扩充,编码方式兼容GB2312。Unicode:几乎收录了各个国家使用的字符,并且还在不断扩充。Unicode仅定义了字符和数值的映射关系。具体存储需要看是UTF-8、UTF-16、UTF-32等。
Unicode字符集
Unicode定义了映射关系,但是却没有规定如何存储。一个码值为 0x41 的字符,只需要 1字节 就可以存下,但是码值 0x9ED1 的字符需要 2字节 的空间才可以装下,而更靠后的字符可能会需要 3字节 甚至 4字节 的空间。
UTF-16 和 UTF-32
我们可以规定,一个字符使用四个字节存储,也就是 32 位,这样就能涵盖现有 Unicode 包含的所有字符,这种编码方式叫做 UTF-32(UCS Transformation Format 的缩写)。UTF-32 的规则虽然简单,但是缺陷也很明显,假设使用 UTF-32 和 ASCII 分别对一个只有西文字母的文档编码,前者需要花费的空间是后者的四倍(ASCII 每个字符只需要一个字节存储)。
UTF-16是一种变长字符编码, 它将字符编码成 2 字节 或者 4 字节。与UTF-32类似,同样存在着空间浪费的问题。
UTF-8
在存储和网络传输中,通常使用更为节省空间的变长编码方式 UTF-8,UTF-8 代表 8 位一组表示 Unicode 字符的格式,采用变长编码,使用 1 - 4 个字节来表示字符,比如下面这样:
'C' -> 01000011(十六进制为0x43) // 1字节
'斌' -> 11100110 10010110 10001100(十六进制为0xE6968C) // 3字节
变长编码通常需要存储表示字节数的信息,让计算机知道字符是以几个字节来存储的。
UTF-8用首字节的前几位表示编码的字节数:
- 首字节以0开头,表示单字节编码
- 首字节以110开头,表示双字节编码,后续字节以10开头
- 首字节以1110开头,表示三字节编码,后续字节以10开头
- 首字节以11110开头,表示四字节编码,后续字节以10开头

举个例子,就拿上方代码块的 ‘斌’ 这个字符,
-
通过中文转Unicode编码工具可知码值为 \u658C。
-
转换为二进制数
01100101 10001100,我们得到码点后采用UTF-8将其存储到计算机中,我们需要16位有效比特位,从上图可以看出只要 3字节 即可表示。 -
将二进制数代入规则:1110
01101001 01101000 1100(红色字体为有效比特位)
字符集和比较规则的应用
各级别的字符集和比较规则
在MySQL中可以从服务器、数据库、表、列这几个维度分别设置和查看字符集及其比较规则。
服务器级别
| 系统变量 | 描述 |
|---|---|
| character_set_server | 服务器级别的字符集 |
| collation_server | 服务器级别的比较规则 |
MySQL8.0中默认的服务器字符集为utf8mb4,比较规则为utf8mb4_0900_ai_ci。
mysql> SHOW variables like 'character_set_server';
+----------------------+---------+
| Variable_name | Value |
+----------------------+---------+
| character_set_server | utf8mb4 |
+----------------------+---------+mysql> SHOW variables like 'collation_server';
+------------------+--------------------+
| Variable_name | Value |
+------------------+--------------------+
| collation_server | utf8mb4_0900_ai_ci |
+------------------+--------------------+
修改MySQL系统变量的方式可以通过启动选项或者在服务器程序运行过程中使用SET语句来修改。也可以修改配置文件的*[server]*组信息。
数据库级别
具体数据库的字符集和比较规则可以在创建是指定,创建后也可以通过ALTER语句来修改。
# 创建或修改数据库时指定字符集
(CREATE | ALTER) DATABASE 数据库名称[CHARACTER SET 字符集名称][COLLATE 比较规则名称];
| 系统变量 | 描述 |
|---|---|
| character_set_database | 当前数据库的字符集 |
| collation_database | 当前数据库的比较规则 |
数据库级别的两个系统变量与服务器级别不同的是,这我们不能通过修改这两个变量的值来改变当前数据库的字符集和比较规则(修改可以通过ALTER语句)。
创建数据库时也可以不指定字符集和比较规则,这将默认使用服务器级别的值。
表级别
与数据库级别类似,表的字符集和比较规则也可以在创建表时指定,或创建后修改。
# 创建表时指定
CREATE TABLE 表名 (列信息)[CHARACTER SET 字符集名称][COLLATE 比较规则名称];# 修改表的字符集
ALTER TABLE 表名[CHARACTER SET 字符集名称][COLLATE 比较规则名称];
创建数据库时同样可以不指定字符集和比较规则,这将继承数据库级别。
列级别
对于存储字符串的列,同一个表中不同的列可以有不同的字符集和比较规则。在创建和修改列的时候可以指定该列的字符集和比较规则。
# 创建时指定
CREATE TABLE 表名(列名 字符串类型 [CHARACTER SET 字符集名称] [COLLATE 比较规则名称],...
);# 修改列的字符集
ALTER TABLE 表名 MODIFY 列名 字符串类型 [CHARACTER SET 字符集] [COLLATE 比较规则名称];
同样,如果没有指定,就会使用表级别的。需要注意的是,修改指定列的字符集时,如果列中存储的数据不能用修改后的字符集进行表示,则会发生错误,中断修改操作。
小结:各级别的字符集和比较规则
- 如果创建或修改列时没有显式指定字符集和比较规则,则默认使用表的字符集和比较规则。
- 如果创建表时没有显式指定,则默认使用数据库的。
- 如果创建数据库时没有显式指定,则该数据库默认使用服务器的。
知道列的字符集后,就能知道某个列存储的实际数据所占用的存储空间大小。
客户端和服务器通信过程中的字符集
什么是乱码?计算机对某个字节序列进行解码时,采用的字符集和编码时使用的字符集不一致,就会产生乱码。例如’我’在utf-8下字节序列为0xE68891,若采用GBK解码,会先读前两个字节。
客户端发送阶段
使用MySQL自带的mysql客户端程序发送请求时(如下图),客户端编码请求字符串时使用的字符集与操作系统当前使用的字符集一致。

在Windows系统中,可以在启动客户端时使用命令default-character-set指定字符集(Unix系统慎用,指定字符集与操作系统不一致时,会乱码)。
mysql --default-character-set=utf8
在连接服务端时,客户端将默认的字符集信息(或者通过上述方式指定字符集)与用户名、密码等信息一起发送给服务器。服务端收到后将character_set_client、character_set_connetion、character_set_results这3个系统变量的值初始化为客户端传递的字符集,作用请参考 2.2.2 节。
服务端处理阶段
| 系统变量 | 描述 |
|---|---|
| character_set_client | 服务器认为请求是按照该系统变量指定的字符集进行编码 |
| character_set_connection | 服务器处理请求时,把请求字节序列从character_set_client转换为character_set_connection对应的字符集 |
| character_set_results | 服务器采用该系统变量指定的字符集对返回给客户端的字符串进行编码 |
- 接收请求
服务端接收到客户端的请求的字节序列时,根据系统变量character_set_client对应的字符集解码该字节序列,该变量是SESSION级别的,可以对不同客户端设置不同的解码规则。
- 处理请求
在真正处理请求时,又会将其转换为系统变量character_set_connection对应的字符集进行编码的字节序列,该变量也是SESSION级别的,与之配套的另一个变量是collation_connection。
将字节序列根据 character_set_client 转码为 character_set_connection 是为了确保数据在不同环节中的一致性、避免字符集不匹配问题、提高系统的灵活性和兼容性。这样可以保证 MySQL 在处理请求时能够正确解析和处理不同字符集编码的数据,确保数据的完整性和准确性。
CREATE TABLE table1(col VARCHAR(100)
) ENGINE=InnoDB CHARSET=utf8;
假设当前的character_set_connection为GBK。
当执行如下查询语句:
SELECT * FROM table1 WHERE col = '斌';
表中的col字段是UTF-8编码,但连接为GBK,在这种情况下,列的字符集和排序规则的优先级会更高,因此会将 ‘斌’ 从 GBK 转为 UTF-8 后,使用 c 列的比较规则进行比较。
- 返回结果
服务端将查询结果从对应列的字符集编码转换为character_set_results系统变量对应的字符集编码后的字节序列,之后再发送给客户端。该变量亦是SESSION级别的。
客户端接收结果阶段
在此阶段,客户端收到的响应也是一个字节序列。对于Windows系统,客户端会使用MySQL客户端的默认字符集来解码这个字节序列(启动项 –default-character-set)。但是 Unix 系统会使用系统默认编码直接输出到控制台,因此可能会产生乱码。如下场景:
- 查看当前操作系统的默认编码

-
在 Mac OS 启动MySQL客户端时使用
–default_character_set=gbk。 -
客户端与服务端建立连接时指定了编码方式为 GBK ,因此服务端将会返回 GBK 编码后的字节序列。

- Mac OS 会直接将序列输出到终端,使用的是系统的编码 UTF-8 ,因此出现乱码(windows会使用客户端的编码)。

相关文章:
MySQL字符集和比较规则
MySQL字符集和比较规则 字符集和比较规则简介 字符集: 描述字符与二进制数据的映射关系 比较规则:比较指定字符集中的字符的规则 字符集 我们知道,计算机无法直接存储字符串,实际存储的都是二进制数据。字符集是有限的ÿ…...
备忘录模式(Memento Pattern)
定义 备忘录模式(Memento Pattern)是一种行为设计模式,它允许在不破坏封装性的前提下捕获一个对象的内部状态,并在以后将对象恢复到该状态。备忘录模式通常用于实现撤销操作(Undo)或历史记录(H…...
LeetCode 刷题 [C++] 第121题.买卖股票的最佳时机
题目描述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的…...
ORACLE 基础
一.ORACLE简介 1.1什么是oracle ORACLE 数据库系统是美国 ORACLE 公司(甲骨文)提供的以分布式数据库为核心的一组软件产品,是目前最流行的客户/服务器(CLIENT/SERVER)或 B/S 体系结构的数据库之一。 ORACLE 通常应用于大型系统的数据库产品。…...
Adobe illustrator CEP插件调试
1.创建插件CEP面板,可以参考:http://blog.nullice.com/%E6%8A%80%E6%9C%AF/CEP-%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B/%E6%8A%80%E6%9C%AF-CEP-%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8B-Adobe-CEP-%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E6%95%99%E7%A8%8…...
学会玩游戏,智能究竟从何而来?
最近在读梅拉妮米歇尔《AI 3.0》第三部分第九章,谈到学会玩游戏,智能究竟从何而来? 作者: [美] 梅拉妮米歇尔 出版社: 四川科学技术出版社湛庐 原作名: Artificial Intelligence: A Guide for Thinking Humans 译者: 王飞跃 / 李玉珂 / 王晓…...
Unity 常用操作
2D素材网站 https://craftpix.net/ https://itch.io/game-assets/tag-2d/tag-backgrounds 3D素材资源网址 https://www.mixamo.com/#/ 场景常用操作: 快捷键:QWER Q:Q键或鼠标中键,可以拉动场景。 W:选中物体后&…...
【计算机网络_应用层】协议定制序列化反序列化
文章目录 1. TCP协议的通信流程2. 应用层协议定制3. 通过“网络计算器”的实现来实现应用层协议定制和序列化3.1 protocol3.2 序列化和反序列化3.2.1 手写序列化和反序列化3.2.2 使用Json库 3.3 数据包读取3.4 服务端设计3.5 最后的源代码和运行结果 1. TCP协议的通信流程 在之…...
Doris实战——银联商务实时数仓构建
目录 前言 一、应用场景 二、OLAP选型 三、实时数仓构建 四、实时数仓体系的建设与实践 4.1 数仓分层的合理规划 4.2 分桶分区策略的合理设置 4.3 多源数据迁移方案 4.4 全量与增量数据的同步 4.5 离线数据加工任务迁移 五、金融级数仓稳定性最佳实践 5.1 多租户资…...
代码随想录算法训练营第七天
● 自己看到题目的第一想法 第454题.四数相加II 方法: 方法一: 暴力法 思路: 注意: 代码: class Solution { public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<i…...
文件操作和IO(2):Java中操作文件
目录 一、File的属性 二、File的构造方法 三、File的方法 四、代码示例 1、getName,getParent,getPath方法 2、getAbsolutePath,getCanonicalPath方法 3、exists,isDirectory,createNewFile方法 4、createNewF…...
人工智能-零基础
机缘 扩充下知识栈,准备零基础开始 人工智能零基础 日常 日常水一下博客… 憧憬 努力成为一个会人工智能的程序员...
网络爬虫部分应掌握的重要知识点
目录 一、预备知识1、Web基本工作原理2、网络爬虫的Robots协议 二、爬取网页1、请求服务器并获取网页2、查看服务器端响应的状态码3、输出网页内容 三、使用BeautifulSoup定位网页元素1、首先需要导入BeautifulSoup库2、使用find/find_all函数查找所需的标签元素 四、获取元素的…...
git命令笔记
文章目录 0、参考文档1、常用指令git checkout系列git pull系列git push系列git reset系列git branch系列git log系列git revert 撤销某次提交git diff其他 2、查看和修改用户名和邮箱,生成密钥other 0、参考文档 Git使用教程:最详细、最傻瓜、最浅显、…...
微服务day03-Nacos配置管理与Nacos集群搭建
一.Nacos配置管理 Nacos不仅可以作为注册中心,可以进行配置管理 1.1 统一配置管理 统一配置管理可以实现配置的热更新(即不用重启当服务发生变更时也可以直接更新) dataId格式:服务名-环境名.yaml,分组一般使用默认…...
DFS剪枝
剪枝 将搜索过程中一些不必要的部分剔除掉,因为搜索过程构成了一棵树,剔除不必要的部分,就像是在树上将树枝剪掉,故名剪枝。 剪枝是回溯法中的一种重要优化手段,方法往往先写一个暴力搜索,然后找到某些特…...
基于SpringBoot多模块项目引入其他模块时@Autowired无法注入
基于SpringBoot多模块项目引入其他模块时Autowired无法注入 一、问题描述1、解决方案 一、问题描述 启动Spring Boot项目时报 Could not autowire. No beans of ‘xxxxxxxx’ type found. 没有找到bean的实例,即spring没有实例化对象,也就无法根据配置文…...
每日一题——LeetCode1566.重复至少K次且长度为M的模式
方法一 暴力枚举 var containsPattern function(arr, m, k) {const n arr.length;for (let l 0; l < n - m * k; l) {let offset;for (offset 0; offset < m * k; offset) {if (arr[l offset] ! arr[l offset % m]) {break;}}if (offset m * k) {return true;}}r…...
代码随想录刷题笔记-Day27
1. 全排列 46. 全排列https://leetcode.cn/problems/permutations/ 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1: 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],…...
【小沐学GIS】QGIS安装和入门使用
文章目录 1、简介2、下载和安装3、使用3.1 XYZ Tiles3.2 WMS / WMTS3.3 GeoJson文件加载 4、在线资源结语 1、简介 QGIS是一款开源地理信息系统。该项目于2002年5月诞生,同年6月作为SourceForge上的一个项目建立。QGIS目前运行在大多数Unix平台、Windows和macOS上。…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
Python如何给视频添加音频和字幕
在Python中,给视频添加音频和字幕可以使用电影文件处理库MoviePy和字幕处理库Subtitles。下面将详细介绍如何使用这些库来实现视频的音频和字幕添加,包括必要的代码示例和详细解释。 环境准备 在开始之前,需要安装以下Python库:…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器
一、原理介绍 传统滑模观测器采用如下结构: 传统SMO中LPF会带来相位延迟和幅值衰减,并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF),可以去除高次谐波,并且不用相位补偿就可以获得一个误差较小的转子位…...
自然语言处理——文本分类
文本分类 传统机器学习方法文本表示向量空间模型 特征选择文档频率互信息信息增益(IG) 分类器设计贝叶斯理论:线性判别函数 文本分类性能评估P-R曲线ROC曲线 将文本文档或句子分类为预定义的类或类别, 有单标签多类别文本分类和多…...
