給定一條SQL,如何提取其中的where條件?where條件中的每一個子條件,在SQL執行的過程當中有分別起着什麼樣的做用?數據庫
關係型數據庫中,數據組織涉及到兩個最基本的結構:表與索引。測試
表中存儲的是完整記錄,通常有兩種組織形式:堆表(全部的記錄無序存儲),或者是聚簇索引表(全部的記錄,按照記錄主鍵進行排序存儲)。spa
索引中存儲的是完整記錄的一個子集,用於加速記錄的查詢速度,索引的組織形式,通常均爲B+樹結構。code
測試排序
讓咱們建立一張測試表,爲表新增幾個索引,而後插入幾條記錄,最後看看錶的完整數據組織、存儲結構式怎麼樣的。索引
create table t1 (a int primary key, b int, c int, d int, e varchar(20)); create index idx_t1_bcd on t1(b, c, d); insert into t1 values (4,3,1,1,’d’); insert into t1 values (1,1,1,1,’a’); insert into t1 values (8,8,8,8,’h’): insert into t1 values (2,2,2,2,’b’); insert into t1 values (5,2,3,5,’e’); insert into t1 values (3,3,2,2,’c’); insert into t1 values (7,4,5,5,’g’); insert into t1 values (6,6,4,4,’f’);
t1表的存儲結構以下圖所示(只畫出了idx_t1_bcd索引與t1表結構,沒有包括t1表的主鍵索引):table
idx_t1_bcd索引上有[b,c,d]三個字段(如果InnoDB類的聚簇索引表,idx_t1_bcd上還會包括主鍵a字段),idx_t1_bcd索引,首先按照b字段排序,b字段相同,則按照c字段排序,以此類推ast
考慮如下的一條SQL,會走idx_t1_bcd索引基礎
select * from t1 where b >= 2 and b < 8 and c > 1 and d != 4 and e != ‘a’;
思考這條SQL的幾個關鍵性問題:select
此SQL,覆蓋索引idx_t1_bcd上的哪一個範圍?
起始範圍:記錄[2,2,2]是第一個須要檢查的索引項。索引發始查找範圍由b >= 2,c > 1決定。
終止範圍:記錄[8,8,8]是第一個不須要檢查的記錄,而以前的記錄均須要判斷。索引的終止查找範圍由b < 8決定;
在肯定了查詢的起始、終止範圍以後,SQL中還有哪些條件可使用索引idx_t1_bcd過濾?
固定了索引的查詢範圍[(2,2,2),(8,8,8))以後,此索引範圍中並非每條記錄都是知足where查詢條件的。例如:(3,1,1)不知足c > 1的約束;(6,4,4)不知足d != 4的約束。而c,d列,都可在索引idx_t1_bcd中過濾掉不知足條件的索引記錄的。
所以,SQL中還可使用c > 1 and d != 4條件進行索引記錄的過濾。
在肯定了索引中最終可以過濾掉的條件以後,還有哪些條件是索引沒法過濾的?
顯而易見,e !='a'這個查詢條件,沒法在索引idx_t1_bcd上進行過濾,由於索引並未包含e列。e列只在堆表上存在,爲了過濾此查詢條件,必須將已經知足索引查詢條件的記錄回表,取出表中的e列,而後使用e列的查詢條件e != ‘a’進行最終的過濾。
在理解以上的問題解答的基礎上,作一個抽象,可總結出一套放置於全部SQL語句而皆準的where查詢條件的提取規則:
可概括爲3大類:Index Key (First Key & Last Key),Index Filter,Table Filter。
Index Key
用於肯定SQL查詢在索引中的連續範圍的查詢條件,被稱之爲Index Key。一個範圍包含一個起始與一個終止,所以Index Key也被拆分爲Index First Key和Index Last Key,分別用於定位索引查找的起始,以及索引查詢的終止條件。
Index First Key
提取規則:從索引的第一個鍵值開始,檢查其在where條件中是否存在,若存在而且條件是=、>=,則將對應的條件加入Index First Key之中,繼續讀取索引的下一個鍵值,使用一樣的提取規則;若存在而且條件是>,則將對應的條件加入Index First Key中,而後終止Index First Key的提取。
針對上面的SQL,應用這個提取規則,提取出來的Index First Key爲(b >= 2, c > 1)。因爲c的條件爲 >,提取結束,不包括d。
Index Last Key
與Index First Key正好相反,用於肯定索引查詢的終止範圍。提取規則:從索引的第一個鍵值開始,檢查其在where條件中是否存在,若存在而且條件是=、<=,則將對應條件加入到Index Last Key中,繼續提取索引的下一個鍵值,使用一樣的提取規則;若存在而且條件是 < ,則將條件加入到Index Last Key中,同時終止提取;若不存在,一樣終止Index Last Key的提取。
針對上面的SQL,應用這個提取規則,提取出來的Index Last Key爲(b < 8),因爲是 < 符號,所以提取b以後結束。
Index Filter
在Index Key的提取以後固定了索引的查詢範圍,可是此範圍中的項,並不都是知足查詢條件的項。在上面的SQL用例中,(3,1,1),(6,4,4)均屬於範圍中,可是均不知足SQL的查詢條件。
Index Filter的提取規則:一樣從索引列的第一列開始,檢查其在where條件中是否存在:
1 若存在而且where條件僅爲 =,則跳過第一列繼續檢查索引下一列,下一索引列採起與索引第一列一樣的提取規則;
2 若where條件爲 >=、>、<、<= 其中的幾種,則跳過索引第一列,將其他where條件中索引相關列所有加入到Index Filter之中;
3 若索引第一列的where條件包含 =、>=、>、<、<= 以外的條件,則將此條件以及其他where條件中索引相關列所有加入到Index Filter之中;
4 若第一列不包含查詢條件,則將全部索引相關條件均加入到Index Filter之中。
針對上面的用例SQL,索引第一列只包含 >=、< 兩個條件,所以第一列可跳過,將餘下的c、d兩列加入到Index Filter中。所以得到的Index Filter爲 c > 1 and d != 4 。
Table Filter
Table Filter是最簡單,也是提取最爲方便的。提取規則:全部不屬於索引列的查詢條件,均歸爲Table Filter之中。
針對上面的用例SQL,Table Filter就爲 e != 'a'。
SQL語句中的where條件,使用以上的提取規則,最終都會被提取到Index Key (First Key & Last Key),Index Filter與Table Filter之中。 Index First Key,只是用來定位索引的起始範圍,在索引第一次Search Path(沿着索引B+樹的根節點一直遍歷,到索引正確的葉節點位置)時使用,一次判斷便可; Index Last Key,用來定位索引的終止範圍,所以對於起始範圍以後讀到的每一條索引記錄,均須要判斷是否已經超過了Index Last Key的範圍,若超過,則當前查詢結束; Index Filter,用於過濾索引查詢範圍中不知足查詢條件的記錄,所以對於索引範圍中的每一條記錄,均須要與Index Filter進行對比,若不知足Index Filter則直接丟棄,繼續讀取索引下一條記錄; Table Filter,最後一道where條件的防線,用於過濾經過前面索引的層層考驗的記錄,判斷完整記錄是否知足Table Filter中的查詢條件,若不知足,跳過當前記錄,繼續讀取索引的下一條記錄,若知足,則返回記錄,此記錄知足了where的全部條件。