本文解決了什麼問題:希望通過這些文章能夠幫你更加順暢的了解mysql優化器的行為;在你閱讀mysql源代碼之前了解更多的背後思路。
本文不解決什麼問題:教你如何讀懂源代碼;
這個系列很長,大概按這樣的思路進行下去: 基本的資料結構、文法解析、join的主要算法、join順序和單表通路。資料結構(以及他們的關系)和算法流程總是互相穿插介紹。
建議閱讀:參考文獻中的文章和書籍,都建議在閱讀本文之前閱讀。
mysql文法解析封裝在函數mysqlparser中完成。跟其他的文法解析器一樣,它包含兩個子產品:詞法分析(lexical scanner)和文法規則(grammar rule module)。詞法分析将整個sql語句打碎成一個個單詞(token),而文法規則子產品則根據mysql定義的文法規則生成對應的資料結構,并存儲在對象thd->lex結構當中。最後優化器,根據這裡的資料,生成執行計劃,再調用存儲引擎接口執行。
詞法分析和文法規則子產品有兩個較成熟的開源工具flex和bison分别用來解決這兩個問題。mysql處于性能和靈活考慮,選擇了自己完成詞法解析部分,文法規則部分使用bison。詞法解析和bison溝通的核心函數是由詞法解析器提供的函數接口yylex(),在bison中,必要的時候調用yylex()獲得詞法解析的資料,完成自己的文法解析。bison的入口時yyparse(),在mysql中是,mysqlparse。
如果對詞法分析和文法規則子產品感到陌生,建議閱讀參考文獻[4][5][6]先注1,否則很難了解整個架構,或者至少會有很強的斷層感。而且,根據bison的action追蹤mysql資料的存儲結構是很有效的。
簡單的解析過程可以使用下面的示意圖說明:

具體的解析一個sql語句的where部分:
bison在做文法解析後,會将解析結果(一顆解析樹/ast)存儲在thd::lex中。這裡将通過考察存儲where的資料結構來檢視文法解析的結果。
在了解mysql的解析樹之前,我們需要先來認識一個重要的資料結構item。這是一個基礎對象,在優化器部分代碼,滿地都是。在mysql internal manual中也單獨介紹:the item class。
item是一個基礎類,在他的基礎上派生了很多子孫。這些子類基本描述所有sql語句中的對象,他們包括:
一個文本字元串/數值對象
一個資料表的某一列(例如,select c1,c2 from dual...中的c1,c2)
一個比較動作,例如c1>10
一個where子句的所有資訊
......
可以看到,item基本上代碼sql語句中的所有對象。在文法解析樹中,這些item以一顆樹的形式存在。示意圖如下:
從select子句開始,我們看到對應的where_clause就是我們關注的where:
我們來看看bison中的幾個重要的action參考注1:
根據這裡的bison文法,就可以生産上面的where文法樹了。如果你是和我一樣剛剛了解flex/bison/ast,一定也會決定很巧妙!
繪制了下面的關系圖用來描述where和where解析樹的各個分支:
例如where條件where c1="orczhou" and c2 > 10,where本身(lex->select->where)就是一個item_cond_and對象,這個對象中有一個item list,将list中每一個item的值做and運輸,也就是這個where的取值了。
這裡,where的list中有兩個item對象,分别代表了c1="orczhou"和c2 > 10。具體的,這兩個對象的類型分别是item_func_eq和item_func_gt。
再單獨看看item_func_gt(代表c2 > 10)對象,這個對象由item_func派生而來(當然追根朔源都是item的孩兒們),這個對象有成員:item **args。args則存放了比較操作需要使用的item。
對于c2 > 10,這個不等式中有兩個item,分别代表字段c2和整數10,存儲這兩個對象的類型分别是:item_field和item_int。
where條件是:where id = 531389273 and reg_date > '2012-02-12 09';
列印where中的list
因為where有兩個判斷,是以這裡list中有兩個元素。
列印list中的第一個判斷(id = 531389273)
這裡等于操作有兩個操作元素(arg_count=2),并以數組的形式存儲在args中
列印上面等式的第一個對象(也就是id)
</blockquote>
可以看到這裡的id對象的類型是item::field_item,也就是item_field類型。
繼續從存儲where的item_cond_and對象開始:
(點選可以檢視大圖)
看到item_cond_and的繼承關系:item_cond->item_bool_func->......->item_result_filed->item
item一個很重要的成員函數就是type,是以在gdb的時候如果不清楚item的類型,可以調用該方法确定:
這篇文章就到這吧,希望能夠繼續下去。