MySQL原始碼:從SQL語句到MySQL內部物件
0 寫在前面
本文解決了什麼問題:希望通過這些文章能夠幫你更加順暢的理解MySQL優化器的行為;在你閱讀MySQL原始碼之前瞭解更多的背後思路。
本文不解決什麼問題:教你如何讀懂原始碼;
這個系列很長,大概按這樣的思路進行下去: 基本的資料結構、語法解析、JOIN的主要演算法、JOIN順序和單表訪問。資料結構(以及他們的關係)和演算法流程總是相互穿插介紹。
建議閱讀:參考文獻中的文章和書籍,都建議在閱讀本文之前閱讀。
1 SQL語句解析基礎
1.1 語法解析基礎/Flex與Bison
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資料的儲存結構是很有效的。
1.2 MySQL語法解析Sample與示意圖
簡單的解析過程可以使用下面的示意圖說明:
具體的解析一個SQL語句的WHERE部分:
2 SQL語句到MySQL的內部物件
Bison在做語法解析後,會將解析結果(一顆解析樹/AST)儲存在THD::LEX中。這裡將通過考察儲存WHERE的資料結構來檢視語法解析的結果。
2.1 著名的Item物件
在瞭解MySQL的解析樹之前,我們需要先來認識一個重要的資料結構Item。這是一個基礎物件,在優化器部分程式碼,滿地都是。在MySQL Internal Manual中也單獨介紹:The Item Class。
Item是一個基礎類,在他的基礎上派生了很多子孫。這些子類基本描述所有SQL語句中的物件,他們包括:
一個文字字串/數值物件
一個資料表的某一列(例如,select c1,c2 from dual…中的c1,c2)
一個比較動作,例如c1>10
一個WHERE子句的所有資訊
……
可以看到,Item基本上程式碼SQL語句中的所有物件。在語法解析樹中,這些Item以一顆樹的形式存在。示意圖如下:
2.2 Bison語法中的WHERE
從SELECT子句開始,我們看到對應的where_clause就是我們關注的WHERE:
我們來看看Bison中的幾個重要的Action參考注1:
where_clause:
/* empty */ {}
| WHERE expr
{
THD->lex->current_select->where = $2
}
expr:
...
| expr and expr
{
$$ = new (YYTHD->mem_root) Item_cond_and($1, $3)
}
|ident comp_op NUM /*這一行並不是原始碼的一部分,便於理解簡化如此*/
{
$$ = new Item_func_ge(a, b); /*這一行並不是原始碼的一部分,便於理解簡化如此*/
}
根據這裡的Bison語法,就可以生產上面的WHERE語法樹了。如果你是和我一樣剛剛瞭解Flex/Bison/AST,一定也會決定很巧妙!
2.3 WHERE的資料結構和他們之間的關係
繪製了下面的關係圖用來描述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。
2.4 通過GDB列印WHERE物件
WHERE條件是:WHERE id = 531389273 AND reg_date > `2012-02-12 09`;
列印WHERE中的List
(gdb) p ((Item_cond *)select_lex->where)->list
$13 = {
<base_list> = {
<Sql_alloc> = {<No data fields>},
members of base_list:
first = 0x7f5bbc005860,
last = 0x7f5bbc005870,
elements = 2
}
因為WHERE有兩個判斷,所以這裡list中有兩個元素。
列印list中的第一個判斷(id = 531389273)
(gdb) p *(Item_func *)((Item_cond *)select_lex->where)->list->first->info
$69 = {
<Item_result_field> = {
<Item> = {
......
next = 0x7f2134005320,
......
},
......
},
members of Item_func:
args = 0x7f2134005420,
tmp_arg = {0x7f2134005228, 0x7f2134005320},
arg_count = 2,
.......
}
這裡等於操作有兩個操作元素(arg_count=2),並以陣列的形式儲存在args中
列印上面等式的第一個物件(也就是id)
列印第一個Item的型別 p ((Item_func *)((Item_cond *)select_lex->where)->list->first->info)->args[0]->type() $74 = Item::FIELD_ITEM 將第一個Item轉換成正確的型別再列印 p *(Item_field *)((Item_func *)((Item_cond *)select_lex->where)->list->first->info)->args[0] $78 = { <Item_ident> = { <Item> = { ....... name = 0x7f2134005208 "id", ...... }, ...... members of Item_ident: orig_field_name = 0x7f2134005208 "id", field_name = 0x7f2134005208 "id", ....... }, members of Item_field: field = 0x0, result_field = 0x0, ....... }
可以看到這裡的id物件的型別是Item::FIELD_ITEM,也就是Item_field型別。
3 關於Item物件
繼續從儲存WHERE的Item_cond_and物件開始:
(點選可以檢視大圖)
看到Item_cond_and的繼承關係:Item_cond->Item_bool_func->……->Item_result_filed->Item
Item一個很重要的成員函式就是type,所以在gdb的時候如果不清楚Item的型別,可以呼叫該方法確定:
(gdb) p ((*(Item_func *)thd->lex->current_select->where)->tmp_arg[0])->type()
$42 = Item::FIELD_ITEM
這篇文章就到這吧,希望能夠繼續下去。
相關文章
- MySql 常用Sql語句MySql
- MYSQL SQL語句優化MySql優化
- mysql捕捉所有SQL語句MySql
- sql 語句練習 In MySQLMySql
- MySQL基本sql語句總結MySql
- mysql 常用sql語句 簡介MySql
- MySQL之SQL語句優化MySql優化
- MySQL中常用的SQL語句MySql
- MySql與Sql Server Update語句MySqlServer
- MYSQL 常用sql語句小結MySql
- mysql sql語句學習(一)MySql
- sql 語句練習(3) In MySQLMySql
- MySQL_通過binlog檢視原始SQL語句MySql
- 自制小工具大大加速MySQL SQL語句優化(附原始碼)MySql優化原始碼
- MySQL內連線查詢語句MySql
- MySQL指南之SQL語句基礎MySql
- MySql常用操作SQL語句彙總MySql
- mysql執行sql語句過程MySql
- mysql的sql語句執行流程MySql
- mysql空間大小的SQL語句MySql
- mysql 查詢建表語句sqlMySql
- MySQL管理之SQL語句例項MySql
- jsp tomcat mysql *SQL*語句JSTomcatMySql
- MySql和簡單的sql語句MySql
- MySQL複製表結構和內容到另一張表中的SQL語句MySql
- mysql語句MySql
- MySQL cron定時執行SQL語句MySql
- mysql查詢效率慢的SQL語句MySql
- MySQL中常用SQL語句的編寫MySql
- MySQL特有的SQL語句 第一彈MySql
- mysql查表空間大小的SQL語句MySql
- MySQL入門---(一)SQL的DDL語句MySql
- 【MySQL】MySQL基礎(SQL語句、約束、資料型別)MySql資料型別
- MySQL replace語句MySql
- MySQL的語句MySql
- mySql常用語句MySql
- MySQL語句大全MySql
- MYSQL語句集MySql