❝人生苦短,不如养狗html
❞
MySQL能够说是一门比较容易上手可是也很容易出错的数据库语言。当你自信满满敲下一行SQL准备不看结果直接英雄式的转身时,不符合预期的执行结果会将你的脸打的 「pia~ pia~」 响。mysql
前段时间闲鱼在写bug时遇到了这样一个需求:按照权重升序查询一组数据,新增的数据必须按照时间出现的列表的后面。看到这个需求,闲鱼想都没想,直接一个 order by
,而后自信回头,不带走一个bug。没想到过两天,产品告诉执行结果不符合预期。本着“你必定是在骗我,看我花式打你的脸”的心态,我执行了一下SQL:web
SELECT * FROM member_tool_config WHERE isv_id IS NULL and user_id IS NULL ORDER BY weight ASC;
复制代码
咦?必定是今天的风有些喧嚣,影响了SQL执行的结果......算了,仍是老老实实查bug。sql
通过一番排查,发现罪魁祸首实际上是 order by
。当使用 order by
的字段存在多行相同值时,就会致使上面出现的乱序问题,这里咱们来看下官方的解释[1]:数据库
❝If multiple rows have identical values in the
❞ORDER BY
columns, the server is free to return those rows in any order, and may do so differently depending on the overall execution plan. In other words, the sort order of those rows is nondeterministic with respect to the nonordered columns.编辑器
注意这里的用词 is free to return those rows in any order
。当出现多行相同值时,MySQL会 「自由奔放」 的以 「任何顺序」 返回结果集。固然也不会那么奔放,官方也在后面说了,可能会根据执行计划不一样最终的执行状况也会不一样,也就是说最终结果是不稳定的。ide
既然官方文档也说了,执行的结果很大程度受执行计划的影响,那么就意味着,在使用 order by
咱们须要明确查询的范围,细化查询条件,让MySQL在执行时更加了解咱们的需求。好比上面的例子,除了使用权重,还能够增长建立时间做为排序的条件之一。具体SQL以下:flex
SELECT * FROM member_tool_config WHERE isv_id IS NULL and user_id IS NULL ORDER BY weight,gmt_create ASC;
复制代码
虽然问题获得了解决,也查看了官方的文档,可是总以为好像有点缺憾。若是哪位大佬有更好的解释能够一块儿交流一下。最后感谢产品经理,让闲鱼在写bug之余也感觉到了MySQL的“有趣”。url
LIMIT Query Optimization: https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.htmlspa
本文使用 mdnice 排版