SQL查詢操作處理流程,SQL操作處理流程

來源:互聯網
上載者:User

SQL查詢操作處理流程,SQL操作處理流程
這裡看到書上講述SQL的查詢處理,在SQL中查詢是通過select語句以及一些輔助的子句來實現需要的輸出,這裡使用的是mysql,首先,要理解物理表和虛擬表的區別,物理表就是儲存在檔案系統上的一個或者多個檔案,按照相應的儲存資料結構將每一行的資料存放區,虛擬表是我們在物理表的基礎上構建出來的,可能是全部的表結構,也可能是表中的部分欄位或者部分行,甚至可能是表中某些欄位經過某種運算之後的結果。但是SQL語言不像C/C++/JAVA這類語言一樣,它們的主要區別在於SQL給你一個需求,不關心它是怎麼實現的,真正的實現由資料庫完成,當然不同的資料庫可能會有差別很大的實現方式,而C/C++這類的語言,我們必須一步步的實現,完成指定的功能。所以SQL的內部實現過程我們不用關心,但是對於查詢請求,它的執行過程和執行順序對我們對結果的認識有很大的影響,但是真正的執行過程需要深入資料庫內部才能明白使用哪些方式(例如索引)最佳化,所以這裡我們重點看一下查詢請求每個子句的執行順序。     標準的SQL查詢語句的結果如下所示:     (8) SELECT x, xx, xxx, xxxx  \      (9)      DISTINCT <x, xx,...> \     (1)      FROM <table1, table2, table3,...>  \     (3)      <join_type>JOIN<join_table>  \      (2)      ON  <join_condition>   \     (4)      WHERE  <where_condition>  \     (5)      GROUP BY <group_by_list>  \     (6)      WITH[CUBE | ROLLUP]   \     (7)      HAVING  <having_condition>  \      (10)    ORDER BY <order_by_list>   \     (11)    LIMIT <limit_number> OFFSET <offset_number> ;
每個子句執行的次序已經在前面進行了標記,在一一介紹這些子句之前,我們要先明白,執行這個命令的輸入是這些表名、條件(ON、WHERE和HAVING)以及一些欄位名(SELECT,DISTINCT、ORDER BY、GROUP BY),其中表名標識的是實體儲存體的表,欄位名是每一個表的欄位的名稱,條件是針對欄位的或者該欄位上執行的聚集合函式的值得邏輯運算式。這些子句的每一步都是產生一個邏輯關係表。1)、FROM操作,這一步的輸入是多個表,在這一步是對多個關係表執行笛卡爾積操作,產生的結果是VT1,假設有3個表,t1、t2和t3,三個表分別有r1、r2、r3行,每個表有c1、c2、c3個欄位,那麼執行笛卡爾積得到的VT1則有r1*r2*r3行,有c1+c2+c3個欄位。2)、這一步是在第一步產生的VT的基礎之上執行的判斷操作,ON後面的邏輯運算式是一個針對VT1表上的每一行的判斷,我們將淘汰不滿足ON條件的行,但是一般情況下,我們執行邏輯操作返回的結果總是TRUE或者FALSE,但是在SQL中,可能存在第三個值,那就是NULL,這個一般被認為空白(注意,不是Null 字元串),它既不是TRUE也不是FALSE,我們來看:mysql> select NULL = NULL \G*************************** 1. row ***************************NULL = NULL: NULL
mysql> select 0 = NULL \G*************************** 1. row ***************************0 = NULL: NULL
mysql> select 1 = NULL \G*************************** 1. row ***************************1 = NULL: NULL
mysql> select NULL != NULL \G*************************** 1. row ***************************NULL != NULL: NULL

     所以,我們可以把NULL視為未知狀態,所以兩個未知狀態也不是相等的。但是在條件判斷的時候,我們要分出TRUE或者FALSE,因為我們要根據這個結果判斷是否淘汰這一行,在ON子句中,是將NULL視為FALSE的,所以如果某一行的該欄位是NULL,那麼它將會被淘汰。例如:


接著,我們看一下將這一個表執行完笛卡爾積之後再執行ON操作得到的結果:


可以看出,在執行笛卡爾積之後產生的VT1表應該含有9行,其中t2.b應該包含‘hello’、‘world和’NULL三種,這裡只返回了‘world’,所以在判斷NULL != 'hello'的時候雖然返回的是NULL,但是ON子句把它當做了FALSE。     所以在ON子句的操作之後,得到了表2,這裡面只包含滿足ON後面邏輯操作計算得到TRUE的行(淘汰計算結果為FALSE或者NULL的行)。3)、這一步執行的是添加外部行的操作,這裡針對的是外部JOIN的,因為外部JOIN需要保證進行串連的左邊的表或者右邊的表中每一行都出現在VT2中,但是如果在ON操作的時候這一行被淘汰了呢?那麼就進行補充添加,僅僅根據左串連或者右串連添加上左邊或者右邊表中缺失的行,然後其它的欄位補充NULL就可以了,得到了VT3。

可以從上例中看到,在笛卡爾積計算之後,一共產生了9行,然後執行ON操作,只剩下了3行滿足條件的,而條件是t2.b!='hello',這就導致了t2表中只剩下了b='hello'的那一行,如上上一個圖所示,但是如果執行了右外串連的操作,那麼需要添加t2表(因為t2是串連操作右邊的那個表)中缺失的每一行(這裡需要添加兩行),對於這兩行除了t2欄位外的其他欄位,都補充NULL就可以了。如果將 上例中的t1和t2換一下,然後再講right join換成left join,可以得到類似的結果,只不過補充的NULL出現在是右邊。4)、這一步執行的是我們最熟悉的WHERE子句,這一步是在VT3的基礎上執行條件過濾,同樣,只保留條件計算得到TRUE的行,淘汰結果為FALSE和NULL的行。將返回的結果標記為VT4。

但是,在WHERE子句執行的時候需要注意一些問題:     1、由於WHERE是第四步執行的,而此時並沒有執行GROUP BY子句,所以不能再WHERE子句中使用聚集合函式運算之後的結果作為條件運算的輸入,這將會導致執行出錯。     mysql> select * from T1 as t1 right join  T1 as t2 on t2.b != 'hello' where count(t1.b) != 1;
ERROR 1111 (HY000): Invalid use of group function     2、由於在執行WHERE的時候並沒有執行到SELECT操作,所以在SELECT操作中出現的as別名將不能用在WHERE子句中。     mysql> select t1.a as A from T1 as t1 right join  T1 as t2 on t2.b != 'hello' A != 10;     ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server      version for the right syntax to use near 'A != 10' at line 1     3、要明確WHERE是在添加缺失行之後執行的,而ON執行在添加缺失行之前,所以如果在ON和WHERE使用相同的邏輯計算,得到的結果可能不是相同的。5)、這一步執行的是分組的操作,在VT4的基礎上,根據GROUP BY確定的列進行分組,在GROUP BY子句中會認為所有的NULL都是相同的,而不是NULL != NULL,將它們分在一組,例如:

6)、with子句分為ROLLUP和CUBE兩種,這兩種我們基本上用不到,CUBE在mysql也不支援,ROLLUP只是在得到的結果添加額外的一行。

這裡不探討ROLLUP的作用了,假設它產生的結果為VT67)、執行HAVING子句,這個子句的作用也是將匯聚之後的每一組(在GROUP BY指定的列上相同的行為一組)進行判斷,這是有區別與ON和WHERE子句的,它們都是對於上一個操作結果中的每一行進行判斷,而HAVING是對每一組。這裡可以是對一個或者多個欄位的判斷,也可以是每一個組中執行匯聚函數的判斷。產生的結果是VT7。     但是,在HAVING執行的時候需要注意,雖然在GROUP BY的時候將執行列為NULL的劃分到同一組了,但是對於某一列為NULL的時候,執行這一列的count操作會被認為為0的,例如:

但是在計算count(*)的時候,某一行即使都是NULL,也會被算作一行的,例如:
這一點需要在具體的應用上特別注意,尤其是使用OUTER JOIN的時候會添加一些NULL,可能由於使用count(*)而不是count(欄位名)導致不正確的計數。8)、這一步執行的是SELECT操作,然後SELECT出現在查詢語句的最前面,但是它是到了第八步才被執行,這一步是對VT7上的選擇SELECT指定的列。產生VT8。另外,在SELECT中不能對前面欄位的別名進行使用,也就是SELECT的別名只有在整個SELECT子句執行完之後才有效。

這一點需要在具體的應用上特別注意,尤其是使用OUTER JOIN的時候會添加一些NULL,可能由於使用count(*)而不是count(欄位名)導致不正確的計數。8)、這一步執行的是SELECT操作,然後SELECT出現在查詢語句的最前面,但是它是到了第八步才被執行,這一步是對VT7上的選擇SELECT指定的列。產生VT8。另外,在SELECT中不能對前面欄位的別名進行使用,也就是SELECT的別名只有在整個SELECT子句執行完之後才有效。

11)、最後一步執行的是OFFSET ... LIMIT子句,這一步就是在上面產生的VT10表中,從指定的OFFSET開始選擇指定的行數,OFFSET也可以省略,而寫成LIMIT m, n.它的含義和LIMIT n OFFSET m是一樣的。
好了,一般的SQL查詢語句都是按照這個順序執行的,當然具體的邏輯查詢和物理查詢方案這裡我們沒有涉及,僅僅是介紹每一步的執行順序和它的作用,當然其中還涉及一些mysql中的規則,以後使用SQL查詢語句之前要首先理好這個順序,然後再去考慮使用什麼樣的查詢語句才能得到希望的結果。

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.