SQL邏輯查詢語句執(zhí)行順序

一、SELECT語句關(guān)鍵字的定義順序
SELECT DISTINCT <select_list>
FROM <left_table>
<join_type> JOIN <right_table>
ON <join_condition>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
ORDER BY <order_by_condition>
LIMIT <limit_number>
二主之、SELECT語句的關(guān)鍵字執(zhí)行順序
(7)     SELECT 
(8)     DISTINCT <select_list>
(1)     FROM <left_table>
(3)     <join_type> JOIN <right_table>
(2)     ON <join_condition>
(4)     WHERE <where_condition>
(5)     GROUP BY <group_by_list>
(6)     HAVING <having_condition>
(9)     ORDER BY <order_by_condition>
(10)    LIMIT <limit_number>
三酵幕、準(zhǔn)備表和數(shù)據(jù)
  1. 新建一個(gè)測(cè)試數(shù)據(jù)庫TestDB;
create database TestDB;

2.創(chuàng)建測(cè)試表table1和table2缓艳;

CREATE TABLE table1
 (
     customer_id VARCHAR(10) NOT NULL,
     city VARCHAR(10) NOT NULL,
     PRIMARY KEY(customer_id)
 )ENGINE=INNODB DEFAULT CHARSET=UTF8;

 CREATE TABLE table2
 (
     order_id INT NOT NULL auto_increment,
     customer_id VARCHAR(10),
     PRIMARY KEY(order_id)
 )ENGINE=INNODB DEFAULT CHARSET=UTF8;

3.插入測(cè)試數(shù)據(jù)校摩;

INSERT INTO table1(customer_id,city) VALUES('163','hangzhou');
 INSERT INTO table1(customer_id,city) VALUES('9you','shanghai');
 INSERT INTO table1(customer_id,city) VALUES('tx','hangzhou');
 INSERT INTO table1(customer_id,city) VALUES('baidu','hangzhou');

 INSERT INTO table2(customer_id) VALUES('163');
 INSERT INTO table2(customer_id) VALUES('163');
 INSERT INTO table2(customer_id) VALUES('9you');
 INSERT INTO table2(customer_id) VALUES('9you');
 INSERT INTO table2(customer_id) VALUES('9you');
 INSERT INTO table2(customer_id) VALUES('tx');
 INSERT INTO table2(customer_id) VALUES(NULL);

準(zhǔn)備工作做完以后,table1和table2看起來應(yīng)該像下面這樣:

mysql> select * from table1;
 +-------------+----------+
 | customer_id | city     |
 +-------------+----------+
 | 163         | hangzhou |
 | 9you        | shanghai |
 | baidu       | hangzhou |
 | tx          | hangzhou |
 +-------------+----------+
rows in set (0.00 sec)

 mysql> select * from table2;
 +----------+-------------+
 | order_id | customer_id |
 +----------+-------------+
 |        1 | 163         |
 |        2 | 163         |
 |        3 | 9you        |
 |        4 | 9you        |
 |        5 | 9you        |
 |        6 | tx          |
 |        7 | NULL        |
 +----------+-------------+
rows in set (0.00 sec)
四 準(zhǔn)備SQL邏輯查詢測(cè)試語句
#查詢來自杭州阶淘,并且訂單數(shù)少于2的客戶衙吩。
 SELECT a.customer_id, COUNT(b.order_id) as total_orders
 FROM table1 AS a
 LEFT JOIN table2 AS b
 ON a.customer_id = b.customer_id
 WHERE a.city = 'hangzhou'
 GROUP BY a.customer_id
 HAVING count(b.order_id) < 2
 ORDER BY total_orders DESC;
五 執(zhí)行順序分析

在這些SQL語句的執(zhí)行過程中,都會(huì)產(chǎn)生一個(gè)虛擬表溪窒,用來保存SQL語句的執(zhí)行結(jié)果(這是重點(diǎn))坤塞,我現(xiàn)在就來跟蹤這個(gè)虛擬表的變化,得到最終的查詢結(jié)果的過程澈蚌,來分析整個(gè)SQL邏輯查詢的執(zhí)行順序和過程摹芙。

執(zhí)行from語句

第一步,執(zhí)行FROM語句宛瞄。我們首先需要知道最開始從哪個(gè)表開始的浮禾,這就是FROM告訴我們的。現(xiàn)在有了<left_table>和<right_table>兩個(gè)表,我們到底從哪個(gè)表開始盈电,還是從兩個(gè)表進(jìn)行某種聯(lián)系以后再開始呢蝴簇?它們之間如何產(chǎn)生聯(lián)系呢?——笛卡爾積

關(guān)于什么是笛卡爾積挣轨,請(qǐng)自行Google補(bǔ)腦军熏。經(jīng)過FROM語句對(duì)兩個(gè)表執(zhí)行笛卡爾積,會(huì)得到一個(gè)虛擬表卷扮,暫且叫VT1(vitual table 1)荡澎,內(nèi)容如下:

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | hangzhou |        1 | 163         |
| 9you        | shanghai |        1 | 163         |
| baidu       | hangzhou |        1 | 163         |
| tx          | hangzhou |        1 | 163         |
| 163         | hangzhou |        2 | 163         |
| 9you        | shanghai |        2 | 163         |
| baidu       | hangzhou |        2 | 163         |
| tx          | hangzhou |        2 | 163         |
| 163         | hangzhou |        3 | 9you        |
| 9you        | shanghai |        3 | 9you        |
| baidu       | hangzhou |        3 | 9you        |
| tx          | hangzhou |        3 | 9you        |
| 163         | hangzhou |        4 | 9you        |
| 9you        | shanghai |        4 | 9you        |
| baidu       | hangzhou |        4 | 9you        |
| tx          | hangzhou |        4 | 9you        |
| 163         | hangzhou |        5 | 9you        |
| 9you        | shanghai |        5 | 9you        |
| baidu       | hangzhou |        5 | 9you        |
| tx          | hangzhou |        5 | 9you        |
| 163         | hangzhou |        6 | tx          |
| 9you        | shanghai |        6 | tx          |
| baidu       | hangzhou |        6 | tx          |
| tx          | hangzhou |        6 | tx          |
| 163         | hangzhou |        7 | NULL        |
| 9you        | shanghai |        7 | NULL        |
| baidu       | hangzhou |        7 | NULL        |
| tx          | hangzhou |        7 | NULL        |
+-------------+----------+----------+-------------+

總共有28(table1的記錄條數(shù) * table2的記錄條數(shù))條記錄。這就是VT1的結(jié)果晤锹,接下來的操作就在VT1的基礎(chǔ)上進(jìn)行摩幔。

執(zhí)行ON過濾

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | hangzhou |        1 | 163         |
| 163         | hangzhou |        2 | 163         |
| 9you        | shanghai |        3 | 9you        |
| 9you        | shanghai |        4 | 9you        |
| 9you        | shanghai |        5 | 9you        |
| tx          | hangzhou |        6 | tx          |
+-------------+----------+----------+-------------+

VT2就是經(jīng)過ON條件篩選以后得到的有用數(shù)據(jù),而接下來的操作將在VT2的基礎(chǔ)上繼續(xù)進(jìn)行鞭铆。

添加外部行

這一步只有在連接類型為OUTER JOIN時(shí)才發(fā)生或衡,如LEFT OUTER JOIN、RIGHT OUTER JOIN和FULL OUTER JOIN车遂。在大多數(shù)的時(shí)候封断,我們都是會(huì)省略掉OUTER關(guān)鍵字的,但OUTER表示的就是外部行的概念舶担。

LEFT OUTER JOIN把左表記為保留表坡疼,得到的結(jié)果為:

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | hangzhou |        1 | 163         |
| 163         | hangzhou |        2 | 163         |
| 9you        | shanghai |        3 | 9you        |
| 9you        | shanghai |        4 | 9you        |
| 9you        | shanghai |        5 | 9you        |
| tx          | hangzhou |        6 | tx          |
| baidu       | hangzhou |     NULL | NULL        |
+-------------+----------+----------+-------------+

RIGHT OUTER JOIN把右表記為保留表,得到的結(jié)果為:

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | hangzhou |        1 | 163         |
| 163         | hangzhou |        2 | 163         |
| 9you        | shanghai |        3 | 9you        |
| 9you        | shanghai |        4 | 9you        |
| 9you        | shanghai |        5 | 9you        |
| tx          | hangzhou |        6 | tx          |
| NULL        | NULL     |        7 | NULL        |
+-------------+----------+----------+-------------+

FULL OUTER JOIN把左右表都作為保留表衣陶,得到的結(jié)果為:

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | hangzhou |        1 | 163         |
| 163         | hangzhou |        2 | 163         |
| 9you        | shanghai |        3 | 9you        |
| 9you        | shanghai |        4 | 9you        |
| 9you        | shanghai |        5 | 9you        |
| tx          | hangzhou |        6 | tx          |
| baidu       | hangzhou |     NULL | NULL        |
| NULL        | NULL     |        7 | NULL        |
+-------------+----------+----------+-------------+

添加外部行的工作就是在VT2表的基礎(chǔ)上添加保留表中被過濾條件過濾掉的數(shù)據(jù)柄瑰,非保留表中的數(shù)據(jù)被賦予NULL值,最后生成虛擬表VT3剪况。

由于我在準(zhǔn)備的測(cè)試SQL查詢邏輯語句中使用的是LEFT JOIN教沾,過濾掉了以下這條數(shù)據(jù):

| baidu       | hangzhou |     NULL | NULL        |

現(xiàn)在就把這條數(shù)據(jù)添加到VT2表中,得到的VT3表如下:

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | hangzhou |        1 | 163         |
| 163         | hangzhou |        2 | 163         |
| 9you        | shanghai |        3 | 9you        |
| 9you        | shanghai |        4 | 9you        |
| 9you        | shanghai |        5 | 9you        |
| tx          | hangzhou |        6 | tx          |
| baidu       | hangzhou |     NULL | NULL        |
+-------------+----------+----------+-------------+

接下來的操作都會(huì)在該VT3表上進(jìn)行译断。

執(zhí)行WHERE過濾

對(duì)添加外部行得到的VT3進(jìn)行WHERE過濾授翻,只有符合<where_condition>的記錄才會(huì)輸出到虛擬表VT4中。當(dāng)我們執(zhí)行WHERE a.city = 'hangzhou'的時(shí)候孙咪,就會(huì)得到以下內(nèi)容藏姐,并存在虛擬表VT4中:

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | hangzhou |        1 | 163         |
| 163         | hangzhou |        2 | 163         |
| tx          | hangzhou |        6 | tx          |
| baidu       | hangzhou |     NULL | NULL        |
+-------------+----------+----------+-------------+

但是在使用WHERE子句時(shí),需要注意以下兩點(diǎn):

由于數(shù)據(jù)還沒有分組该贾,因此現(xiàn)在還不能在WHERE過濾器中使用where_condition=MIN(col)這類對(duì)分組統(tǒng)計(jì)的過濾;
由于還沒有進(jìn)行列的選取操作捌臊,因此在SELECT中使用列的別名也是不被允許的杨蛋,如:SELECT city as c FROM t WHERE c='shanghai';是不允許出現(xiàn)的。

執(zhí)行GROUP BY分組

GROU BY子句主要是對(duì)使用WHERE子句得到的虛擬表進(jìn)行分組操作。我們執(zhí)行測(cè)試語句中的GROUP BY a.customer_id逞力,就會(huì)得到以下內(nèi)容(默認(rèn)只顯示組內(nèi)第一條):

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| 163         | hangzhou |        1 | 163         |
| baidu       | hangzhou |     NULL | NULL        |
| tx          | hangzhou |        6 | tx          |
+-------------+----------+----------+-------------+

得到的內(nèi)容會(huì)存入虛擬表VT5中曙寡,此時(shí),我們就得到了一個(gè)VT5虛擬表寇荧,接下來的操作都會(huì)在該表上完成举庶。

執(zhí)行HAVING過濾

HAVING子句主要和GROUP BY子句配合使用,對(duì)分組得到的VT5虛擬表進(jìn)行條件過濾揩抡。當(dāng)我執(zhí)行測(cè)試語句中的HAVING count(b.order_id) < 2時(shí)户侥,將得到以下內(nèi)容:

+-------------+----------+----------+-------------+
| customer_id | city     | order_id | customer_id |
+-------------+----------+----------+-------------+
| baidu       | hangzhou |     NULL | NULL        |
| tx          | hangzhou |        6 | tx          |
+-------------+----------+----------+-------------+

SELECT列表

現(xiàn)在才會(huì)執(zhí)行到SELECT子句,不要以為SELECT子句被寫在第一行峦嗤,就是第一個(gè)被執(zhí)行的蕊唐。

我們執(zhí)行測(cè)試語句中的SELECT a.customer_id, COUNT(b.order_id) as total_orders,從虛擬表VT6中選擇出我們需要的內(nèi)容烁设。我們將得到以下內(nèi)容:

+-------------+--------------+
| customer_id | total_orders |
+-------------+--------------+
| baidu       |            0 |
| tx          |            1 |
+-------------+--------------+

執(zhí)行DISTINCT子句

如果在查詢中指定了DISTINCT子句替梨,則會(huì)創(chuàng)建一張內(nèi)存臨時(shí)表(如果內(nèi)存放不下,就需要存放在硬盤了)装黑。這張臨時(shí)表的表結(jié)構(gòu)和上一步產(chǎn)生的虛擬表VT7是一樣的副瀑,不同的是對(duì)進(jìn)行DISTINCT操作的列增加了一個(gè)唯一索引,以此來除重復(fù)數(shù)據(jù)恋谭。

由于我的測(cè)試SQL語句中并沒有使用DISTINCT糠睡,所以,在該查詢中箕别,這一步不會(huì)生成一個(gè)虛擬表铜幽。

執(zhí)行ORDER BY子句

對(duì)虛擬表中的內(nèi)容按照指定的列進(jìn)行排序,然后返回一個(gè)新的虛擬表串稀,我們執(zhí)行測(cè)試SQL語句中的ORDER BY total_orders DESC除抛,就會(huì)得到以下內(nèi)容:

+-------------+--------------+
| customer_id | total_orders |
+-------------+--------------+
| tx          |            1 |
| baidu       |            0 |
+-------------+--------------+

執(zhí)行LIMIT子句

LIMIT子句從上一步得到的VT8虛擬表中選出從指定位置開始的指定行數(shù)據(jù)。對(duì)于沒有應(yīng)用ORDER BY的LIMIT子句母截,得到的結(jié)果同樣是無序的到忽,所以,很多時(shí)候清寇,我們都會(huì)看到LIMIT子句會(huì)和ORDER BY子句一起使用喘漏。

MySQL數(shù)據(jù)庫的LIMIT支持如下形式的選擇:

LIMIT n, m

表示從第n條記錄開始選擇m條記錄。而很多開發(fā)人員喜歡使用該語句來解決分頁問題华烟。對(duì)于小數(shù)據(jù)翩迈,使用LIMIT子句沒有任何問題,當(dāng)數(shù)據(jù)量非常大的時(shí)候盔夜,使用LIMIT n, m是非常低效的负饲。因?yàn)長(zhǎng)IMIT的機(jī)制是每次都是從頭開始掃描堤魁,如果需要從第60萬行開始,讀取3條數(shù)據(jù)返十,就需要先掃描定位到60萬行妥泉,然后再進(jìn)行讀取,而掃描的過程是一個(gè)非常低效的過程洞坑。所以盲链,對(duì)于大數(shù)據(jù)處理時(shí),是非常有必要在應(yīng)用層建立一定的緩存機(jī)制(現(xiàn)在的大數(shù)據(jù)處理迟杂,大都使用緩存)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刽沾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逢慌,更是在濱河造成了極大的恐慌悠轩,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攻泼,死亡現(xiàn)場(chǎng)離奇詭異火架,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)忙菠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門何鸡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人牛欢,你說我怎么就攤上這事骡男。” “怎么了傍睹?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵隔盛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我拾稳,道長(zhǎng)吮炕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任访得,我火速辦了婚禮龙亲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘悍抑。我一直安慰自己鳄炉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布搜骡。 她就那樣靜靜地躺著拂盯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪记靡。 梳的紋絲不亂的頭發(fā)上磕仅,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天珊豹,我揣著相機(jī)與錄音,去河邊找鬼榕订。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蜕便,可吹牛的內(nèi)容都是我干的劫恒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼轿腺,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼两嘴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起族壳,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤憔辫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后仿荆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贰您,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年拢操,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锦亦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡令境,死狀恐怖杠园,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舔庶,我是刑警寧澤抛蚁,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站惕橙,受9級(jí)特大地震影響瞧甩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吕漂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一亲配、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惶凝,春花似錦吼虎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至混滔,卻和暖如春洒疚,著一層夾襖步出監(jiān)牢的瞬間歹颓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工油湖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巍扛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓乏德,卻偏偏與公主長(zhǎng)得像撤奸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子喊括,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 2017年 8月15日 星期二 艷陽天 每好的一天從清晨開始胧瓜, 在清晨醒來,好心情就是從看見美麗日出的一霎那開始郑什,...
    新加坡秀英閱讀 336評(píng)論 0 0
  • 不知道從什么時(shí)候開始 我喜歡寫一些東西 我筆寫我心 用文字來表達(dá)自己的內(nèi)心 初始府喳,都是動(dòng)筆寫 后來都比較忙,而且也...
    晨初v聽雨閱讀 218評(píng)論 0 1
  • 今天下午給父母視頻聊天舱沧,是侄子發(fā)的視頻,才知道姐姐把父母接到她們樓上來了偶洋,真是很開心的熟吏, 姐姐這座樓房很大,平時(shí)也...
    請(qǐng)叫我陳姐閱讀 241評(píng)論 0 0
  • 背景:2018年第一篇不想寫得太無趣玄窝,所以補(bǔ)充一篇拖了很久的觀后感牵寺。 編劇似乎為了讓人物更貼近生活,所以除了畢十三...
    霸天斯基閱讀 1,348評(píng)論 0 0
  • 綠海的叔叔問我做生意最重要的是什么恩脂,我也不知道帽氓,誠信,他說不是俩块,算錢的時(shí)候要認(rèn)真(?? . ??)
    木頭她媽呢閱讀 266評(píng)論 0 1