MySQL存储引擎-执行流程
引言
本节通过分析show engines语句,理清sql语句的基本执行流程。关于MySQL协议
与网络处理这里略过,建议大家了解一下协议。对分析MySQL问题很有帮助,
有时利用tcpdump分析MySQL报文更高效。
SQL解析相关
这个条SQL语句虽简单,细究起来其实也颇为费解。这里首先说明一下SQL解析,
简单的说,SQL解析就是将SQL语句转换为一些的对象,这些对象构成语法分析树。
SQL解析是非常复杂繁琐的功能,需要将所有SQL语句匹配构成语法分析树,
其核心的两个工具yacc与lex。MySQL实现了lex词法分析模块,利用开源软件bison实现
语法分析模块,涉及的文件如下:
/**************
sql_lex.cc
sql_lex.h
sql_lex_hash.cc
sql_lex_hash.h
sql_lex_hints.cc
sql_lex_hints.h
sql_yacc.cc //自动生成的文件
sql_yacc.h
sql_yacc.yy
****************/
虽说只八个文件,但其复杂度却是指数级。但大家仍需要了解基本的yacc语法知识,
了解SQL语句解析过程,能够读懂sql_yacc.yy文件中内容。随后分析过程中,会涉
及sql_yacc.yy文件中内容。
函数调用
分析语句执行流程,函数流程如下:
/*****************************************
利用gdb调试工具,通过断点方式追踪,获得的堆栈信息。
*****************************************/
handle_connection();
//connection_handler_per_thread.cc
/* 对于每个Client,MySQL另起一个Pthread线程,
运行此函数处理连接直至断开。
其中for与while双重循环,挺nice的设计
*/
do_command(); //sql_parse.cc
/* 阻塞等待读取网络输入,就是客户发送的请求报文。
分析报文类型,涉及MySQL协议,需大家了解一下MySQL协议。
协议规定了报文,前4个字节格式固定,随后为数据内容。
其中前3个字节,数据内容长度,第四个字节报文序号。
数据内容的第一个字节为报文类型。
*/
dispatch_command(); //sql_parse.cc
/* 根据报文类型,做第一次分发处理。
show engines属于COM_QUERY报文类型。
*/
mysql_parse(); //sql_parse.cc
/* 确实是否缓存了query结果,若存在则直接响应。
调用parse_sql解析sql,构造查询语法分析树,匹配sql_yacc.yy文件11709行。
将show engines语句转换为对INFORMATION_SCHEMA.ENGINES的SELECT操作。
prepare_schema_table
make_schema_select
make_old_format
add_table_to_list
*/
mysql_execute_command();
/*根据SQL类型,做二次分发, SELECT类型*/
execute_sqlcom_select(); //sql_select.cc
open_tables_for_query() //sql_base.cc
open_tables(); //sql_base.cc
open_and_process_table(); //sql_base.cc
mysql_schema_table(); //sql_show.cc
create_schema_table(); //sql_show.cc
create_tmp_table(); //sql_tmp_file.cc
/* Open所有将操作的表,INFORMATION_SCHEMA是虚拟的数据库,
其中的表是虚拟表,需要构造表的Schema。
创建其ENGINES表memory引擎对应的handler对象,将其赋给Table对象的file属性。
【Table与handler关联起来】
*/
handle_query(); //sql_select.cc
prepare();
optimize();
/* 处理了SQL的优化操作,后续分析SQL优化处理*/
JOIN::exec(); //sql_executor.cc
JOIN::prepare_result() //sql_select.cc
get_schema_tables_result(); //sql_show.cc
do_fill_table(); //sql_show.cc
fill_schema_engines(); //sql_show.cc
plugin_foreach_with_mask(); //sql_plugin.cc
iter_schema_engines(); //sql_show.cc
schema_table_store_record(); //sql_show.cc
table->file->ha_write_row();
/* 全局plugin_hash中类型为存储引擎的插件,进行遍历操作,
将数据构建为ENGINES表的记录。并将其存入memory引擎的ENGINES表中。
*/
send_result_set_metadata();
//ENGINES表SCHEMA信息发送至Client
/*Server最复杂核心逻辑之一,后续分析SELECT操作*/
do_select();
//回退到dispatch_command,并执行如下语句后,至此执行完成。
//client显示数据集
send_statement_status();
Protocol_classic::send_eof();
net_send_ok();
net_flush();
net_write_packet();
query_cache_insert();
总结
这里只分析了主干流程,细节都未完成剖析,走马观花而已。通过流程分析,
可看出简单的show engines语句的执行,并不是想象中的那么简单。
上篇分析了Engine插件的初始化操作,现已了解Engine如何与Table建立关联。
接下来介绍如何将leveldb作为存储引擎集成到MySQL中。