一、字符集和校验规则
字符集是一套符号和编码,校验规则(collation)是在字符集内用于比较字符的一套规则,即字符集的排序规则。
MySQL服务器可以支持多种字符集,在同一台服务器,同一个数据库,甚至同一个表的不同字段都可以指定使用不同的字符集,相比oracle等其他数据库管理系统,在同一个数据库只能使用相同的字符集,MySQL明显存在更大的灵活性,但是灵活并不是一件好事情。
每种字符集都可能有多种校对规则,并且都有一个默认的校对规则,并且每个校对规则只是针对某个字符集,和其他的字符集没有关系。
首先创建一个表,ddl语句如下:
CREATE TABLE `t_test_20191029_ci` (`id` char(25) NOT NULL ,`name_id` varchar(20) DEFAULT NULL,`name` text DEFAULT NULL,`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;CREATE TABLE `t_test_20191029_bin` (`id` char(25) NOT NULL ,`name_id` varchar(20) DEFAULT NULL,`name` text DEFAULT NULL,`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
上面建表语句相信大部分同学都能懂,但是对COLLATE=utf8mb4_general_ci或许有点懵逼,大部分同学看到这都会骂娘:这tm到底是什么sb东西,字符集难道不是前面CHARSET=utf8mb4,算了不管了,反正不影响我撸代码。
我们的故事从骂娘开始。
1.1 COLLATE作用
其实COLLATE是字符集中用于排序的一个校验规则。在mysql中,字符类型的列,比如:char、text、varchar等类型的列,都需要有collate和mysql进行交互,告诉mysql这些列该如何进行排序。因此,COLLATE和orderby、distinct、group by、having语句息息相关,同时也会影响where条件中大于小于等于的查询。
另外,如果mysql创建索引的列是字符类型,也会影响该索引创建,因为mysql索引实质有序的排列的数据结构,所以只要跟字符类型比较或排序的地方,都会和COLLATE属性有联系。
1.2 COLLATE的区别
COLLATE通常是和数据字符集(CHARSET)相关的,一般来说每种CHARSET都有多种它所支持的COLLATE,并且每种CHARSET都指定一种COLLATE为默认值。例如Latin1编码的默认COLLATE为latin1_swedish_ci,GBK编码的默认COLLATE为gbk_chinese_ci,utf8mb4编码的默认值为utf8mb4_general_ci。
COLLATE都带有_ci,这是Case Insensitive单词的缩写,就是和大小写无关,"A"和"a"在排序和比较的时候是一视同仁的。selection * from test where cloumn="a"同样可以把cloumn为"A"的值选出来。以_cs后缀的COLLATE,则是Case Sensitive,即大小写敏感的。
到此我们对最开始创建的两个表做一个小小的测试,dml语句如下:
insert into t_test_20191029_ci (id) values('A');insert into t_test_20191029_ci (id) values('a');insert into t_test_20191029_ci (id) values('Aa');insert into t_test_20191029_bin (id) values('A');insert into t_test_20191029_bin (id) values('a');insert into t_test_20191029_bin (id) values('Aa');
然后我们分别查询下id='A':
select * from t_test_20191029_ci where id='A';+----+---------+------+---------------------+| id | name_id | name | create_time |+----+---------+------+---------------------+| A | NULL | NULL | 2019-10-30 16:39:42 || a | NULL | NULL | 2019-10-30 16:39:43 |+----+---------+------+---------------------+2 rows in set (0.01 sec)select * from t_test_20191029_bin where id='A';+----+---------+------+---------------------+| id | name_id | name | create_time |+----+---------+------+---------------------+| A | NULL | NULL | 2019-10-30 16:43:16 |+----+---------+------+---------------------+1 row in set (0.00 sec)
实验结果发现,当校验规则是:utf8mb4_general_ci,该列是不区分大小写的,所以where id='A',会出现两行。省略order by、 having 、group by、distinct的实验,原理是和where一样的。
1.3 类型
mysql中执行show collation命令,可以看到所有字符集的校验规则,因为通常的字符集都是utf8mb4,所以只看该模式下的校验规则。
show collation where Charset ='utf8mb4';+------------------------+---------+-----+---------+----------+---------+| Collation | Charset | Id | Default | Compiled | Sortlen |+------------------------+---------+-----+---------+----------+---------+| utf8mb4_general_ci | utf8mb4 | 45 | Yes | Yes | 1 || utf8mb4_bin | utf8mb4 | 46 | | Yes | 1 || utf8mb4_unicode_ci | utf8mb4 | 224 | | Yes | 8 || utf8mb4_icelandic_ci | utf8mb4 | 225 | | Yes | 8 || utf8mb4_latvian_ci | utf8mb4 | 226 | | Yes | 8 || utf8mb4_romanian_ci | utf8mb4 | 227 | | Yes | 8 || utf8mb4_slovenian_ci | utf8mb4 | 228 | | Yes | 8 || utf8mb4_polish_ci | utf8mb4 | 229 | | Yes | 8 || utf8mb4_estonian_ci | utf8mb4 | 230 | | Yes | 8 || utf8mb4_spanish_ci | utf8mb4 | 231 | | Yes | 8 || utf8mb4_swedish_ci | utf8mb4 | 232 | | Yes | 8 || utf8mb4_turkish_ci | utf8mb4 | 233 | | Yes | 8 || utf8mb4_czech_ci | utf8mb4 | 234 | | Yes | 8 || utf8mb4_danish_ci | utf8mb4 | 235 | | Yes | 8 || utf8mb4_lithuanian_ci | utf8mb4 | 236 | | Yes | 8 || utf8mb4_slovak_ci | utf8mb4 | 237 | | Yes | 8 || utf8mb4_spanish2_ci | utf8mb4 | 238 | | Yes | 8 || utf8mb4_roman_ci | utf8mb4 | 239 | | Yes | 8 || utf8mb4_persian_ci | utf8mb4 | 240 | | Yes | 8 || utf8mb4_esperanto_ci | utf8mb4 | 241 | | Yes | 8 || utf8mb4_hungarian_ci | utf8mb4 | 242 | | Yes | 8 || utf8mb4_sinhala_ci | utf8mb4 | 243 | | Yes | 8 || utf8mb4_german2_ci | utf8mb4 | 244 | | Yes | 8 || utf8mb4_croatian_ci | utf8mb4 | 245 | | Yes | 8 || utf8mb4_unicode_520_ci | utf8mb4 | 246 | | Yes | 8 || utf8mb4_vietnamese_ci | utf8mb4 | 247 | | Yes | 8 |+------------------------+---------+-----+---------+----------+---------+26 rows in set (0.00 sec)
可以看到utf8mb4字符集下,默认校验规则是:utf8mb4_general_ci。
我们常用的校验规则是utf8mb4_general_ci、utf8mb4_unicode_ci、utf8mb4_bin这三个。我们来探究一下这三个的区别:
首先utf8mb4_bin的比较方法其实就是直接将所有字符看作二进制串,然后从最高位往最低位比对。所以很显然它是区分大小写的。
而utf8mb4_unicode_ci和utf8mb4_general_ci对于中文和英文来说,其实是没有任何区别的,但是对于英语之外的其他语言会有一定影响。官方文档使用utf8mb4_unicode_ci,但是对于使用了默认值的系统,也并没有非常排斥,并不认为有什么大问题。对于已经用了utf8mb4_general_ci的系统,也没有必要花时间改造。
另外从mysql 8.0开始,mysql默认的CHARSET已经不再是Latin1了,改为了utf8mb4,并且默认的COLLATE也改为了utf8mb4_0900_ai_ci。utf8mb4_0900_ai_ci就是unicode的进一步细分。
到此我们总结COLLATE到底是什么及其作用:
1、COLLATE是在字符集内用于比较字符的一套规则。、
2、COLLATE只对字符串类型列有效果,比如:varchar、char、text等,对时间类型和数字类型无影响。
3、COLLATE主要有区分大小写(utf8mb4_bin)和不区分大小写(utf8mb4_general_ci)两种。
基于上两点,可以知道以下两点:
1、不同的COLLATE对order by、 having 、group by,以及where 条件的中的大于小于等于有影响。
2、不同的COLLATE下会影响mysql的索引使用。




