MYSQL中的COLLATE是什么?

qcloudcommunity · · 2061 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

> 本文由horstxu发表 在mysql中执行`show create table <tablename>`指令,可以看到一张表的建表语句,example如下: ```js CREATE TABLE `table1` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `field1` text COLLATE utf8_unicode_ci NOT NULL COMMENT '字段1', `field2` varchar(128) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '字段2', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8_unicode_ci; ``` 大部分字段我们都能看懂,但是今天要讨论的是COLLATE关键字。这个值后面对应的`utf8_unicode_ci`是什么意思呢?面试的时候用这个题目考一考DBA,应该可以难倒一大部分人。 # COLLATE是用来做什么的? 使用phpmyadmin的开发可能会非常眼熟,因为其中的中文表头已经给出了答案: ![img](https://ask.qcloudimg.com/draft/1300884/ee0glseost.png?imageView2/2/w/1620)phpmyadmin截图 所谓`utf8_unicode_ci`,其实是用来排序的规则。对于mysql中那些字符类型的列,如`VARCHAR`,`CHAR`,`TEXT`类型的列,都需要有一个`COLLATE`类型来告知mysql如何对该列进行排序和比较。简而言之,**COLLATE会影响到ORDER BY语句的顺序,会影响到WHERE条件中大于小于号筛选出来的结果,会影响**`**DISTINCT**`**、**`**GROUP BY**`**、**`**HAVING**`**语句的查询结果**。另外,mysql建索引的时候,如果索引列是字符类型,也**会影响索引创建**,只不过这种影响我们感知不到。总之,**凡是涉及到字符类型比较或排序的地方,都会和COLLATE有关**。 # 各种COLLATE的区别 `COLLATE`通常是和数据编码(`CHARSET`)相关的,一般来说每种`CHARSET`都有多种它所支持的`COLLATE`,并且每种`CHARSET`都指定一种`COLLATE`为默认值。例如`Latin1`编码的默认`COLLATE`为`latin1_swedish_ci`,`GBK`编码的默认`COLLATE`为`gbk_chinese_ci`,`utf8mb4`编码的默认值为`utf8mb4_general_ci`。 这里顺便讲个题外话,mysql中有`utf8`和`utf8mb4`两种编码,**在mysql中请大家忘记**`**utf8**`**,永远使用**`**utf8mb4**`。这是mysql的一个遗留问题,mysql中的`utf8`最多只能支持3bytes长度的字符编码,对于一些需要占据4bytes的文字,mysql的`utf8`就不支持了,要使用`utf8mb4`才行。 很多`COLLATE`都带有`_ci`字样,这是Case Insensitive的缩写,即大小写无关,也就是说"A"和"a"在排序和比较的时候是一视同仁的。`selection * from table1 where field1="a"`同样可以把field1为"A"的值选出来。与此同时,对于那些`_cs`后缀的`COLLATE`,则是Case Sensitive,即大小写敏感的。 在mysql中使用`show collation`指令可以查看到mysql所支持的所有`COLLATE`。以`utf8mb4`为例,该编码所支持的所有`COLLATE`如下图所示。 ![img](https://ask.qcloudimg.com/draft/1300884/wuhw7ziqob.png?imageView2/2/w/1620)mysql中和utf8mb4相关的所有COLLATE 图中我们能看到很多国家的语言自己的排序规则。在国内比较常用的是`utf8mb4_general_ci`(默认)、`utf8mb4_unicode_ci`、`utf8mb4_bin`这三个。我们来探究一下这三个的区别: 首先`utf8mb4_bin`的比较方法其实就是直接将所有字符看作二进制串,然后从最高位往最低位比对。所以很显然它是区分大小写的。 而`utf8mb4_unicode_ci`和`utf8mb4_general_ci`对于中文和英文来说,其实是没有任何区别的。对于我们开发的国内使用的系统来说,随便选哪个都行。只是对于某些西方国家的字母来说,`utf8mb4_unicode_ci`会比`utf8mb4_general_ci`更符合他们的语言习惯一些,`general`是mysql一个比较老的标准了。例如,德语字母`“ß”`,在`utf8mb4_unicode_ci`中是等价于`"ss"`两个字母的(这是符合德国人习惯的做法),而在`utf8mb4_general_ci`中,它却和字母`“s”`等价。不过,这两种编码的那些微小的区别,对于正常的开发来说,很难感知到。本身我们也很少直接用文字字段去排序,退一步说,即使这个字母排错了一两个,真的能给系统带来灾难性后果么?从网上找的各种帖子讨论来说,更多人推荐使用`utf8mb4_unicode_ci`,但是对于使用了默认值的系统,也并没有非常排斥,并不认为有什么大问题。结论:推荐使用`utf8mb4_unicode_ci`,对于已经用了`utf8mb4_general_ci`的系统,也没有必要花时间改造。 另外需要注意的一点是,从mysql 8.0开始,mysql默认的`CHARSET`已经不再是`Latin1`了,改为了`utf8mb4`([参考链接](https://dev.mysql.com/doc/refman/8.0/en/charset-applications.html)),并且默认的COLLATE也改为了`utf8mb4_0900_ai_ci`。`utf8mb4_0900_ai_ci`大体上就是`unicode`的进一步细分,`0900`指代unicode比较算法的编号( Unicode Collation Algorithm version),`ai`表示accent insensitive(发音无关),例如e, è, é, ê 和 ë是一视同仁的。[相关参考链接1](https://www.monolune.com/what-is-the-utf8mb4_0900_ai_ci-collation/),[相关参考链接2](https://dev.mysql.com/doc/refman/8.0/en/charset-collation-names.html) # COLLATE设置级别及其优先级 设置`COLLATE`可以在示例级别、库级别、表级别、列级别、以及SQL指定。实例级别的`COLLATE`设置就是mysql配置文件或启动指令中的`collation_connection`系统变量。 库级别设置`COLLATE`的语句如下: ```js CREATE DATABASE <db_name> DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ``` 如果库级别没有设置`CHARSET`和`COLLATE`,则库级别默认的`CHARSET`和`COLLATE`使用实例级别的设置。在mysql8.0以下版本中,你如果什么都不修改,默认的`CHARSET`是`Latin1`,默认的`COLLATE`是`latin1_swedish_ci`。从mysql8.0开始,默认的`CHARSET`已经改为了`utf8mb4`,默认的`COLLATE`改为了`utf8mb4_0900_ai_ci`。 表级别的`COLLATE`设置,则是在`CREATE TABLE`的时候加上相关设置语句,例如: ```js CREATE TABLE ( …… ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ``` 如果表级别没有设置`CHARSET`和`COLLATE`,则表级别会继承库级别的`CHARSET`与`COLLATE`。 列级别的设置,则在`CREATE TABLE`中声明列的时候指定,例如 ```js CREATE TABLE ( `field1` VARCHAR(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', …… ) …… ``` 如果列级别没有设置`CHARSET`和`COLATE`,则列级别会继承表级别的`CHARSET`与`COLLATE`。 最后,你也可以在写SQL查询的时候显示声明`COLLATE`来覆盖任何库表列的`COLLATE`设置,不太常用,了解即可: ```js SELECT DISTINCT field1 COLLATE utf8mb4_general_ci FROM table1; SELECT field1, field2 FROM table1 ORDER BY field1 COLLATE utf8mb4_unicode_ci; ``` 如果全都显示设置了,那么优先级顺序是 SQL语句 > 列级别设置 > 表级别设置 > 库级别设置 > 实例级别设置。也就是说列上所指定的`COLLATE`可以覆盖表上指定的`COLLATE`,表上指定的`COLLATE`可以覆盖库级别的`COLLATE`。如果没有指定,则继承下一级的设置。即列上面没有指定`COLLATE`,则该列的`COLLATE`和表上设置的一样。 以上就是关于mysql的`COLLATE`相关知识。不过,在系统设计中,我们还是要尽量避免让系统严重依赖中文字段的排序结果,在mysql的查询中也应该尽量避免使用中文做查询条件。 **此文已由作者授权腾讯云+社区发布,更多原文请[点击](https://cloud.tencent.com/developer/article/1366841?fromSource=waitui )** **搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包!**

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2061 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传