MySQL內核源碼解讀-SQL解析之解析器淺析

MYSQL服務器接收SQL格式的查詢,首先要對sql進行解析,內部將文本格式轉換爲二進制結構,這個轉換就是解析器,解析的目的是爲了讓優化器更好的處理指令,以便以最優的路徑,最少的耗時返回我們想要的結果。
sql解析器的構成:
1、詞法分析(Lexical scanner):作用是將整個查詢分解爲多個元素。
2、語法規則(Grammar rule module):尋找sql語法規則組合,產生一個序列,執行這些規則相關的代碼。
1 and 2 產生一棵解析樹,提供給優化器使用。
mysql解析器的特殊性在於它直接轉換爲程序內存中的內部解析的C/C++結構,而一般的解析器是將文本表達式轉換爲字節代碼。
1. 源碼解讀解析器
MySQL語法解析封裝在函數MYSQLparser中,包含兩個模塊:詞法分析(Lexical scanner)和語法規則(Grammar rule module)。詞法分析將整個SQL語句打碎成一個個單詞(Token),而語法規則模塊則根據MySQL定義的語法規則生成對應的數據結構,並存儲在對象THD->LEX結構當中。最後優化器,根據這裏的數據,生成執行計劃,再調用存儲引擎接口執行。詞法分析和語法規則模塊有兩個較成熟的開源工具Flex和Bison分別用來解決這兩個問題。MySQL出於性能和靈活考慮,選擇了自行完成詞法解析部分,語法規則部分使用Bison。詞法解析和Bison溝通的核心函數是由詞法解析器提供的函數接口yylex(),在Bison中,必要的時候調用yylex()獲得詞法解析的數據,完成自己的語法解析。Bison的入口爲yyparse(),在MySQL中定義爲MYSQLParse。
1.1. 解析示意

Bison在做語法解析後,會將解析結果(解析樹/AST)存儲在THD::LEX中,通過存儲WHERE的數據結構來查看語法解析的結果。

1.2. 解析樹的ITEM對象
在MYSQL中,有以下ITEM大類型:
FIELD_ITEM, FUNC_ITEM,
SUM_FUNC_ITEM,
STRING_ITEM,
INT_ITEM,
REAL_ITEM,
NULL_ITEM,
VARBIN_ITEM,
COPY_STR_ITEM,
FIELD_AVG_ITEM,
DEFAULT_VALUE_ITEM,
PROC_ITEM,COND_ITEM,
REF_ITEM,
FIELD_STD_ITEM,
FIELD_VARIANCE_ITEM,
INSERT_VALUE_ITEM,
SUBSELECT_ITEM,
ROW_ITEM,
CACHE_ITEM,
TYPE_HOLDER,
PARAM_ITEM
其中許多ITEM還有小類,如Item_func有如下小類型:
UNKNOWN_FUNC,
EQ_FUNC,
EQUAL_FUNC,
NE_FUNC,
LT_FUNC,
LE_FUNC,
GE_FUNC,
GT_FUNC,FT_FUNC,
LIKE_FUNC,
NOTLIKE_FUNC,
ISNULL_FUNC,
ISNOTNULL_FUNC,
COND_AND_FUNC,
COND_OR_FUNC,
COND_XOR_FUNC,
BETWEEN, IN_FUNC,
INTERVAL_FUNC,
ISNOTNULLTEST_FUNC,
SP_EQUALS_FUNC,
SP_DISJOINT_FUNC,
SP_INTERSECTS_FUNC,
SP_TOUCHES_FUNC,
SP_CROSSES_FUNC,
SP_WITHIN_FUNC,
SP_CONTAINS_FUNC,
SP_OVERLAPS_FUNC,
SP_STARTPOINT,
SP_ENDPOINT,
SP_EXTERIORRING,
SP_POINTN,
SP_GEOMETRYN,
SP_INTERIORRINGN,
NOT_FUNC,
NOT_ALL_FUNC,
NOW_FUNC,
VAR_VALUE_FUNC
1.3. ITEM語法樹
MySQL內核源碼解讀-SQL解析之解析器淺析
1.4. FIELD 類型
enum enum_field_types {
MYSQL_TYPE_DECIMAL, MYSQL_TYPE_TINY,
MYSQL_TYPE_SHORT,MYSQL_TYPE_LONG,
MYSQL_TYPE_FLOAT,MYSQL_TYPE_DOUBLE,
MYSQL_TYPE_NULL,MYSQL_TYPE_TIMESTAMP,
MYSQL_TYPE_LONGLONG,MYSQL_TYPE_INT24,
MYSQL_TYPE_DATE, MYSQL_TYPE_TIME,
MYSQL_TYPE_DATETIME,MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
MYSQL_TYPE_TINY_BLOB=249,
MYSQL_TYPE_MEDIUM_BLOB=250,
MYSQL_TYPE_LONG_BLOB=251,
MYSQL_TYPE_BLOB=252,
MYSQL_TYPE_VAR_STRING=253,
MYSQL_TYPE_STRING=254,
MYSQL_TYPE_GEOMETRY=255
};
1.5. FIELD和ITEM的關係
通過Item類中的tmp_table_field_from_field_type函數將一個Item類轉化爲一個Filed類返回,例如
Item_int ->Field_longlong
Item_real->Field_double
Item_string->Field_string
1.6. Bison語法中的WHERE

select_from ==>

---->from
join_table_list
where_clause
---->expr or expr
---->expr amd expr
---->……………………
---->simple_expr comp_op simple_expr
  group_clause having_clause
  opt_order_clause
  opt_limit_clause

where 要點:
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); /簡化版/
}

通過解析就能生成where的語法樹。
Where解析樹的分支:如圖
MySQL內核源碼解讀-SQL解析之解析器淺析

1.7. 總結
解析器的最終執行結果就是解析樹,sql語法的複雜性要求具有同樣複雜程度的結構,通過這種結構有效存儲用於執行每個可能使用到的sql語句所需的信息。
解析樹中重要的兩個對象【enum_sql_command和select_lex】, sql_command顯示sql類型,execute_command則指導調用相關函數。通過內核級別的調用,最終生成解析樹,提供給優化器,最終完成我們的操作指令。

2. 參考資料
[1]OReilly Understanding MySQL Internals
[2]MySQL內核:InnoDB存儲引擎
[3]OReilly
[4]《lex與yacc》(第二版)
[5]《flex與bison》(第二版)
[6]Bison操作手冊: http://www.gnu.org/software/bison/manual/bison.html

本文由京東商城數據庫技術部郭光欣提供。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章