❝人生苦短,不如養狗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 排版