MySQL多字段排序的问题
最近在一次开发过程中发现了一个问题,我们都知道MySQL在Order By的时候可以指定多列,会按照指定的顺序依次排序。
例如指定A,B,C列,MySQL会先按A排序,如何A值相同的再按B排序,B值相同的再按C排序。
然后其中还是有不少门道的,例如我就碰到了如下问题,我有一个表test,表结构如下:
1 |
|
其中有如下数据:
A | B | C |
---|---|---|
C料 | 12321 | 123 |
c料 | 测试 | SPHC |
c料 | 测试 | SPHC |
C料 | 测试 | 测试 |
C料 | 测试 | 测试 |
接着执行如下查询
1 |
|
按照我们上面的说法最后出来的结果应该是:
A | B | C |
---|---|---|
C料 | 12321 | 123 |
C料 | 测试 | 测试 |
C料 | 测试 | 测试 |
c料 | 测试 | SPHC |
c料 | 测试 | SPHC |
然而实际出来而结果是:
A | B | C |
---|---|---|
C料 | 12321 | 123 |
c料 | 测试 | SPHC |
c料 | 测试 | SPHC |
C料 | 测试 | 测试 |
C料 | 测试 | 测试 |
可以看到的是A列明显乱序了(注意C大小写),不是说好A相同的排序在一起呢,怎么看起了不对了。
既然是按照列的顺序一个一个排序的,那我们就一个一个排除,看看到底是在哪一列排序出了问题。
执行如下查询:
1 |
|
得到如下结果:
A | B | C |
---|---|---|
C料 | 12321 | 123 |
C料 | 测试 | 测试 |
C料 | 测试 | 测试 |
c料 | 测试 | SPHC |
c料 | 测试 | SPHC |
也就是说在C列加入排序之前,A还是看着有序的,那到底是怎么回事呢?注意回到最开始我们说的MySQL的排序规则,A相同再按B排,B相同按C排。
所以C在加入排序之前,MySQL认为A,B排序后有相同的结果,也就是c料,测试=C料,测试了,所以C加入排序之后可以在前者相同的排序结果中在按C排序。
于是就产生了看起来错误的顺序,这是因为创建表的时候,没有对字段A,B,C指定collation(MYSQL排序依据),默认会使用对应字符集的Collation,
我这里字符集是utf8mb4,对应的默认collation通常是utf8mb4_general_ci,这个collation是大小写不敏感的。
解决办法有两种:
1.更改字段的collation,
1 |
|
使用utf8mb4_bin,这个是大小写敏感的。
2.在排序的时候指定BINARY关键字
1 |
|
因为它会强制MySQL将字段作为二进制字符串对待。
由于这是一个历史存在的表,避免产生其它意向不到的结果,我使用了方法二。至此问题解决。