今天在调试typecho的一个评论排序时发现无论我把排序规则设置为升序还是降序都无法改变最终的排序结果,在仔细检查我的语句后排除了语法出现问题的情况,因此将怀疑的目光定格到mysql上。我在开发中使用的是wamp套装,它集成的是mysql 5.0.51a,到wamp官方网站上发现5.0.51b的模块已经有了,下载下来安装,运行程序发现依然不好使。遂在google上搜索关键词"mysql order bug",第一条即是mysql官方网站上的bug记录,看来找到组织了。看了一下bug描述,跟我的情况差不多,主要是当语句中出现group by时,order by语句就会失效。
在官方网站上对这个bug有较为详细的描述,我理解后大致意思如下:
当我们在GROUP BY中使用主键时,mysql会首先忽略这个声明,因为mysql默认的就是按主键来GROUP BY的。但是如果GROUP BY和ORDER BY同时出现时,我估计是mysql的开发者尝试做一些语句上的优化,它会把GROUP BY里的主键值直接放到ORDER BY里面,而忘了检查GROUP BY和ORDER BY的这两个值是否相同,而且由于GROUP BY里面没有ASC/DESC的描述,写到ORDER BY里面以后同样也只有一个主键值,而在mysql中如果你不写ASC/DESC排序方法,它默认的就是按照ASC来排序,因此你得到排序就总是按主键的升序来排,无论你怎么调整ORDER BY都是这样。
为了让大家理解这个bug,我来写一个问题重现,首先你要使用mysql 5.0.51x版本的数据库,然后请看以下操作和结果
首先我们来看看升序
mysql> SELECT `coid`, `created` FROM typecho_comments GROUP BY typecho_comments.
`coid` ORDER BY typecho_comments.`created` ASC;
+------+------------+
| coid | created |
+------+------------+
| 1 | 1211300209 |
| 2 | 1215627714 |
+------+------------+
2 rows in set (0.02 sec)
没什么问题吧,再来看看降序
mysql> SELECT `coid`, `created` FROM typecho_comments GROUP BY typecho_comments.
`coid` ORDER BY typecho_comments.`created` DESC;
+------+------------+
| coid | created |
+------+------------+
| 1 | 1211300209 |
| 2 | 1215627714 |
+------+------------+
2 rows in set (0.00 sec)
查询结果没有任何变化,而且我们从查询时间也可以看出来,它是直接从缓存中读取的没有经过查询。为了证明我的观点,我们来个猛的
mysql> SELECT `coid`, `created` FROM typecho_comments GROUP BY typecho_comments.
`coid` DESC ORDER BY typecho_comments.`created` DESC;
+------+------------+
| coid | created |
+------+------------+
| 2 | 1215627714 |
| 1 | 1211300209 |
+------+------------+
2 rows in set (0.00 sec)
注意看我的语法,GROUP BY typecho_comments.`coid` DESC,这是一个明显错误的语法,但是如果mysql是直接将GROUP BY放到ORDER BY中的话,它将得到正确的执行。事实证明了我的猜测,而且它还“正确”地倒序了!!
解决方案
升级到mysql 5.0.52以上版本或者降级到mysql 5.0.45以下版本即可。
