環(huán)境
MySQL:5.7
SQL語句的寫法:
select * from (select distinct(a.id) tid, a.* from template_detail a
where a.template_id in (3, 4)
order by a.id desc) tt
group by tt.template_id;
思路:先進行排序访递,然后再進行分組晦嵌,獲取每組的第一條。
Q: 為什么要寫distinct(a.id)呢拷姿?
A:防止合并的構(gòu)造(derived_merge)惭载;
什么是derived_merge?
derived_merge指的是一種查詢優(yōu)化技術(shù)响巢,作用就是把派生表合并到外部的查詢中描滔,提高數(shù)據(jù)檢索的效率。這個特性在MySQL5.7版本中被引入踪古,可以通過如下SQL語句進行查看/開啟/關閉等操作含长。
上面雖然聽起來感覺很牛逼的樣子,但是實際情況是伏穆,這個新特性拘泞,不怎么受歡迎,容易引起錯誤枕扫。
可以通過在子查詢中使用任何阻止合并的構(gòu)造來禁用合并陪腌,盡管這些構(gòu)造對實現(xiàn)的影響并不明確。 防止合并的構(gòu)造對于派生表和視圖引用是相同的:
- 聚合函數(shù)( SUM() 烟瞧, MIN() 诗鸭, MAX() , COUNT()等)
- DISTINCT
- GROUP BY
- HAVING
- LIMIT
- UNION或UNION ALL
- 選擇列表中的子查詢
- 分配給用戶變量
- 僅引用文字值(在這種情況下参滴,沒有基礎表)
子查詢order by失效的場景:
select * from (select a.* from template_detail a
where a.template_id in (3, 4)
order by a.id desc) tt
group by tt.template_id;
假設我們現(xiàn)在把sql中的distinct(a.id) tid,去掉强岸,會發(fā)現(xiàn)子查詢(或者叫:臨時表)中的order by a.id desc失效了。
為什么會這樣呢卵洗?
原理分析:
我們這里使用了臨時表排序请唱,繼而對其結(jié)果進行分組,結(jié)果顯示失敗过蹂,加了distinct(a.id) tid,后結(jié)果正確十绑,原因是因為臨時表(派生表derived table)中使用order by且使其生效,必須滿足三個條件:
- 外部查詢禁止分組或者聚合
- 外部查詢未指定having酷勺, order by
- 外部查詢將派生表或者視圖作為from句中唯一指定源
不滿足這三個條件本橙,order by會被忽略。
一旦外部表使用了group by脆诉,那么臨時表(派生表 derived table)將不會執(zhí)行filesort操作(即order by 會被忽略)甚亭。之后我使用了limit可以使其生效,原因是因為要使派生表order by生效击胜,派生表可以通過使用group by亏狰、limit、having偶摔、distinct等等使其生效(方法有好多暇唾,詳情可看文檔https://dev.mysql.com/doc/refman/5.7/en/derived-table-optimization.html)
原文鏈接:
https://blog.csdn.net/u013066244/article/details/116461584