目录

mysql 如何查看,修改 collate

问题

今天偶然发现 mysql 在比较字符时会忽略大小写,这让我非常意外。

比如 select 'a' = 'A' 这行运行的结果是 1也就是在 mysql 看来 aA 是相等的

经过一番的查找原来是 mysql 的 collate 属性造成的

collate

我们在创建数据库是一般都是直接 create database <name>

如果需要使用 utf8 字符集会在后面指定 database 的字符集create database <name> character set utf8mb4

但除了charset 属性还有collate 属性是可以设置(如下),collate 就是和大小写敏感有关

1
2
3
CREATE DATABASE <name>
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_general_ci;

collate 的作用

对于mysql中那些字符类型的列,如VARCHARCHARTEXT类型的列,都需要有一个COLLATE类型来告知mysql如何对该列进行排序和比较。简而言之,COLLATE会影响到ORDER BY语句的顺序,会影响到WHERE条件中大于小于号筛选出来的结果,会影响DISTINCTGROUP BYHAVING语句的查询结果。另外,mysql建索引的时候,如果索引列是字符类型,也会影响索引创建,只不过这种影响我们感知不到。总之,凡是涉及到字符类型比较或排序的地方,都会和COLLATE有关

collate 的后缀

collate 有三种后缀

  • _ci : case insensitive 的缩写,即大小写无关。例如:utf8mb4_general_ci
  • _cs : case sensitive 的缩写 ,即大小写有关
  • _bin :把字符看作二进制串,然后从最高位往最低位比对。所以很显然它是区分大小写的。例如 utf8mb4_bin

其他

  • 在 mysql 5.7 中 utf8 编码的默认 collateutf8mb4_general_ci
  • show collation 可以查看 mysql 所有支持的 collate

查看 collate

从上面的信息 得出collate 是影响查询大小写敏感的关键,所以接下来肯定是想要看看目前的数据库,表的 collate 值是什么,是不是以 _ci 结尾

查询 database 的 collate

1
2
3
4
5
SELECT SCHEMA_NAME                'database',
       DEFAULT_CHARACTER_SET_NAME 'charset',
       DEFAULT_COLLATION_NAME     'collation'
FROM information_schema.SCHEMATA
where SCHEMA_NAME = 'collate_test_db';

结果:

1
2
3
4
5
+-----------------+---------+--------------------+
| database        | charset | collation          |
+-----------------+---------+--------------------+
| collate_test_db | utf8mb4 | utf8mb4_general_ci |
+-----------------+---------+--------------------+

查询表的 collate

1
2
3
select TABLE_SCHEMA, TABLE_COLLATION
from information_schema.TABLES
where TABLE_NAME = 'collate_test_table'

结果:

1
2
3
4
5
+-----------------+--------------------+
| TABLE_SCHEMA    | TABLE_COLLATION    |
+-----------------+--------------------+
| collate_test_db | utf8mb4_general_ci |
+-----------------+--------------------+

查询列的 collate

1
SHOW FULL COLUMNS FROM <table_name>;

修改 collate

从上面看出的数据库和表都是 _ci 后缀的,所以下面就是把后缀改为 _bin

database 层级的修改

1
ALTER DATABASE collate_test_db DEFAULT CHARACTER SET utf8mb4 COLLATE = utf8mb4_bin;

这只是修改了 database 的默认 collate ,不会对已经存在的表进行修改

table 层级的修改

⚠️ 注意下面有两个 sql :第一个 sql 只会修改 table 的默认 collate ,不会修改已经存在字段的 collate 。第二个 sql 不但会修改默认的 collate ,还会修改已存在的字段。所以推荐使用第二个 sql

1
ALTER TABLE collate_test_table  CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
1
ALTER TABLE collate_test_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;

批量生成修改 collate 的sql

如果一个 database 内的 table 过多,一个个写 alter sql 太麻烦了,可以批量生成

1
2
3
4
5
6
SELECT CONCAT('ALTER TABLE `', TABLE_NAME,
              '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;')
           AS target_tables
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'collate_test_db'
  AND TABLE_TYPE = 'BASE TABLE'

结果:

1
2
3
4
5
6
7
8
9
+------------------------------------------------------------------------------------------+
| target_tables                                                                            |
+------------------------------------------------------------------------------------------+
| ALTER TABLE `collate_test_table` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;   |
| ALTER TABLE `collate_test_table_1` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; |
| ALTER TABLE `collate_test_table_2` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; |
| ALTER TABLE `collate_test_table_3` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; |
| ALTER TABLE `collate_test_table_4` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; |
+------------------------------------------------------------------------------------------+

参考