上一篇講Mysql基本架構時,以"sql查詢語句在MySql架構中具體是怎麼執行的" 進行了全面的講解。知道了sql查詢語句在MySql架構中的具體執行流程,可是爲了可以更好更快的寫出sql語句,我以爲很是有必要知道sql語句中各子句的執行順序。看過上一篇文章的小夥伴應該都知道,sql語句最後各子句的執行應該是在執行器中完成的,存儲引擎對執行器提供的數據讀寫接口。如今開始咱們的學習程序員
全部的 查詢語句都是從from開始執行的,在執行過程當中,每一個步驟都會爲下一個步驟生成一個虛擬表,這個虛擬表將做爲下一個執行步驟的輸入。sql
form是一次查詢語句的開端。數據庫
若是from後面是多張表,join關聯,會首先對前兩個表執行一個笛卡爾乘積,這時候就會生成第一個虛擬表T1(注意:這裏會選擇相對小的表做爲基礎表);編程
對虛表T1進行ON篩選,只有那些符合的行纔會被記錄在虛表T2中。(注意,這裏的這裏若是還有第三個表與之關聯,會用T2與第三個表進行笛卡爾乘積生產T3表,繼續重複3. on步驟生成T4表,不過下面的順序講解暫時不針對這裏的T3和T4,只是從一個表關聯查詢T2繼續說)緩存
對虛擬表T2進行WHERE條件過濾。只有符合的記錄纔會被插入到虛擬表T3中。微信
group by 子句將中的惟一的值組合成爲一組,獲得虛擬表T4。若是應用了group by,那麼後面的全部步驟都只能操做T4的列或者是執行6.聚合函數(count、sum、avg等)。(注意:緣由在於分組後最終的結果集中只包含每一個組中的一行。謹記,否則這裏會出現不少問題,下面的代碼誤區會特別說。)數據結構
聚合函數只是對分組的結果進行一些處理,拿到某些想要的聚合值,例如求和,統計數量等,並不生成虛擬表。架構
應用having篩選器,生成T5。HAVING子句主要和GROUP BY子句配合使用,having篩選器是第一個也是爲惟一一個應用到已分組數據的篩選器。ide
執行select操做,選擇指定的列,插入到虛擬表T6中。函數
對T6中的記錄進行去重。移除相同的行,產生虛擬表T7.(注意:事實上若是應用了group by子句那麼distinct是多餘的,緣由一樣在於,分組的時候是將列中惟一的值分紅一組,同時只爲每一組返回一行記錄,那麼因此的記錄都將是不相同的。 )
應用order by子句。按照order_by_condition排序T7,此時返回的一個遊標,而不是虛擬表。sql是基於集合的理論的,集合不會預先對他的行排序,它只是成員的邏輯集合,成員的順序是可有可無的。對錶進行排序的查詢能夠返回一個對象,這個對象包含特定的物理順序的邏輯組織。這個對象就叫遊標。
oder by的幾點說明
取出指定行的記錄,產生虛擬表T9, 並將結果返回。
limit後面的參數能夠是 一個limit m ,也能夠是limit m n,表示從第m條到第n條數據。
(注意:不少開發人員喜歡使用該語句來解決分頁問題。對於小數據,使用LIMIT子句沒有任何問題,當數據量很是大的時候,使用LIMIT n, m是很是低效的。由於LIMIT的機制是每次都是從頭開始掃描,若是須要從第60萬行開始,讀取3條數據,就須要先掃描定位到60萬行,而後再進行讀取,而掃描的過程是一個很是低效的過程。因此,對於大數據處理時,是很是有必要在應用層創建必定的緩存機制)
SELECT `userspk`.`avatar` AS `user_avatar`,
`a`.`user_id`,
`a`.`answer_record`,
MAX(`score`) AS `score`
FROM (select * from pkrecord order by score desc) as a
INNER JOIN `userspk` AS `userspk`
ON `a`.`user_id` = `userspk`.`user_id`
WHERE `a`.`status` = 1
AND `a`.`user_id` != 'm_6da5d9e0-4629-11e9-b5f7-694ced396953'
GROUP BY `user_id`
ORDER BY `a`.`score` DESC
LIMIT 9;
複製代碼
查詢結果:
想要查詢pk記錄表中分數最高的9個用戶記錄和他們的頭像。
pk記錄表的數據結構設計,每一個用戶天天每一個館下可能會有多條記錄,因此須要進行分組,而且查詢結果只想拿到每一個分組內最高的那條記錄。
這段sql的一些說明:
看一下代碼和執行結果與帶有子查詢的進行比較,就能理解我上面說的一段話:
//不使用子查詢
SELECT `userspk`.`avatar` AS `user_avatar`,
`pkrecord`.`user_id`,
`pkrecord`.`answer_record`,
`pkrecord`.`id`,
MAX(`score`) AS `score`
FROM pkrecord
INNER JOIN `userspk` AS `userspk`
ON `pkrecord`.`user_id` = `userspk`.`user_id`
WHERE `pkrecord`.`status` = 1
AND `pkrecord`.`user_id` != 'm_6da5d9e0-4629-11e9-b5f7-694ced396953'
GROUP BY `user_id`
ORDER BY `pkrecord`.`score` DESC
LIMIT 9;
複製代碼
查詢結果
在 SQL 語句中,能夠爲表名稱及字段(列)名稱指定別名
同時查詢兩張表的數據的時候: 未設置別名前:
SELECT article.title,article.content,user.username FROM article, user
複製代碼WHERE article.aid=1 AND article.uid=user.uid 複製代碼
設置別名後:
SELECT a.title,a.content,u.username FROM article AS a, user AS u where a.aid=1 and a.uid=u.uid
複製代碼
好處:使用表別名查詢,可使 SQL 變得簡潔而更易書寫和閱讀,尤爲在 SQL 比較複雜的狀況下
查詢一張表,直接對查詢字段設置別名
SELECT username AS name,email FROM user
複製代碼
查詢兩張表
好處:字段別名一個明顯的效果是能夠自定義查詢數據返回的字段名;當兩張表有相同的字段須要都被查詢出,使用別名能夠完美的進行區分,避免衝突
SELECT a.title AS atitle,u.username,u.title AS utitle FROM article AS a, user AS u where a.uid=u.uid
複製代碼
關聯查詢時候,關聯表自身的時候,一些分類表,必須使用別名。
別名也能夠在group by與having的時候均可使用
別名能夠在order by排序的時候被使用
查看上面一段sql
delete , update MySQL均可以使用別名,別名在多表(級聯)刪除尤其有用
delete t1,t2 from t_a t1 , t_b t2 where t1.id = t2.id
複製代碼
子查詢結果須要使用別名
查看上面一段sql
select user_id,name from User where user_id = ‘10000050’
複製代碼
在有min、max、distinct、order by、group by操做的列上建索引,避免額外的排序開銷(索引相關)
當心使用or操做,and操做中任何一個子句可以使用索引都會提升查詢性能,可是or條件中任何一個不能使用索引,都將致使查詢性能降低,如where member_no = 1 or provider_no = 1,在member_no或provider_no任何一個字段上沒有索引,都將致使表掃描或聚簇索引掃描(索引相關)
Between通常比in/or高效得多,若是能在between和in/or條件中選擇,那麼始終選擇between條件,並用>=和<=條件組合替代between子句,由於不是全部數據庫的優化器都能把between子句改寫爲>=和<=條件組合,若是不能改寫將致使沒法使用索引(索引相關)
調整join操做順序以使性能最優,join操做是自頂向下的,儘可能把結果集小的兩個表關聯放在前面,可提升性能。(join相關) 注意:索引和關聯我會單獨拿出來兩篇文章進行詳細講解,在這個注意事項中只是簡單提一下。
兩篇文章一塊兒學習能完全搞懂sql語句到底怎麼在架構中執行的,到底應該怎麼寫優秀的sql。
歡迎你們關注個人公衆號——程序員成長指北。請自行微信搜索——「程序員成長指北」