註意本文是SQL執行順序,不是MySQL Server內部執行流程。 MySQL並非像PostgreSQL(被認為是最接近 SQL 標準的資料庫之一)一樣嚴格按照SQL標準,MySQL執行引擎會根據查詢的具體情況和優化策略來決定具體的執行順序,所以SQL執行順序是理論順序。 書寫順序 select. ...
註意本文是SQL執行順序,不是MySQL Server內部執行流程。
MySQL並非像PostgreSQL(被認為是最接近 SQL 標準的資料庫之一)一樣嚴格按照SQL標準,MySQL執行引擎會根據查詢的具體情況和優化策略來決定具體的執行順序,所以SQL執行順序是理論順序。
書寫順序
select...from...join...on...where...group by...having...order by...limit...
執行順序
from->join->on->where->group by->having->select->order by->limit
SQL書寫順序與執行順序不一致的原因?
SQL語言設計受到了數學中的關係代數和元組演算的影響。這些數學理論中並沒有考慮操作順序,歷史原因造成SQL書寫上的差異。
中國的語法是姓在前名在後,英文的反過來。國內是年月日,英文是月日年,文化上的差異,也是造成SQL順序彆扭的原因之一。
SQL執行順序的邏輯是什麼?
- from用於確定操作對象,放第一位毋庸置疑。
- join和on用於關聯,後面的各種處理邏輯依附於關聯後內部創建的臨時表,先生成數據集,才能為後續處理做基礎。
- where用於篩選,可以減少後續操作的數據量,提高查詢性能。
- group by用於對數據進行分類彙總,不放where前面,是為了避免分組後的數據被where過濾掉(分組分了個寂寞),造成算力浪費和記憶體資源(數據量大還是很消耗算力和記憶體的)的問題。
- having用於對分組結果進行過濾,所以要在group by之後。
- select用於決定迭代顯示那些列,而不是限制只有這些列才可以參與處理,上游的各種操作(如複雜的where條件)不能受select欄位的影響,這也是where後面跟的欄位,不必在select出現的原因。select的本意是處理數據後僅僅返回這些欄位,而不是決定只有這些欄位進行數據處理,所以必定要放偏後的位置。
- order by用於結果進行排序,肯定是結果處理後才排序的,理由和group by相似。
- limit用於限制返回結果的行數和偏移量,必須是等篩選完分組完拍完序之後再限制,否則可能導致結果有誤。
為什麼SQL執行不是先group by再where?
先分組再篩選,邏輯上說的過去,相當於整理好數據再篩選,類似於創建索引和使用索引的過程,這也是問題的由來。
如果group by放在where之前執行,則需要對大量數據進行分組,分組後還要對每個組進行篩選,事先分組好的部分數據又被過濾掉了,造成算力和記憶體浪費,可能導致記憶體不足或者性能問題,這不是一個優秀的選擇,倒不如先篩選過濾大量數據,然後對少量數據分組。
為什麼SQL執行要先select再order by?
嘗試select field2 from table order by field1,select後面沒跟order by後面的field1也不報錯。
根據結果反推:select影響不到order by,所以先order by在select也說的過去。
但是:select欄位的別名可以在order by中使用,如果反過來就達不到這樣的效果了。
為什麼MySQL的where比having效率更高?
mysql執行時,先執行from用於定位操作對象,然後就是where,可能百萬條的數據經過where之後只剩下幾十條,然後在進行之後的操作。而group by比where多了一個環節。
聚合函數參與篩選條件,為什麼只能用having?
//報錯,Invalid use of group function
select field from table where avg(field) > 2
//需要修改為
select field from table group by field having avg(field) > 2
聚合函數(常見的avg、sum、count、min、max)需要在分組之後才能計算,執行到where時還沒有分組,此時對分組進行數據處理,所以報錯。相當於要喝一口還沒生產的可樂,不符合事物的發展規律。
為什麼使用聚合函數有分組的前提?
所謂聚合函數,就是對一組數據進行彙總計算,所以有分組的前提。即便沒有使用group by顯式聲明,SQL也會對上游過來的數據集進行預設分組(隱式分組)。
為什麼欄位別名不能在where中使用?
where執行在select之前,此時別名未生效。
為什麼group by和having執行順序優先於select,卻可以使用欄位別名?
可以肯定進行了預載入,不然一定找不到別名,會報錯的。
參考官網:https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html
文章說:標準 SQL 也不允許在子句中使用別名,MySQL擴展了標準SQL以允許別名。標準 SQL 不允許在子句中使用別名,MySQL擴展了標準SQL,詳細的底層原理,文檔並未說明。