一条查询语句在mysql 源代码的执行路径
使用mysql数据库已经有好几年的时间,一直没有时间去研究mysql的内部执行过程,只能通过一些固定的
思维导向和理论去猜测问题出现的缘由,最近有时间探查一下mysql的源码。
main方法
mysql的启动方法也是main方法,并非用java语言编写,而是c和c++语言编写的。
一条查询语句大概会经过下面几个模块的处理:
- 网络连接监听;
- 线程池处理请求;
- 查询解析器;
- 查询优化器;
- 查询执行;
handle_connections_socket() 监听网络连接
–> create_new_thread() 创建业务处理线程
–>start_cached_thread() 从线程池中拿线程
–>pthread_create 创建一个新的线程
–>handler_one_connection() 处理连接
–>do_command() 对从网络通信代码读入的所有命令依次进行处理
–>dispatch_command() 分发SQL命令
–>alloc_query() 把查询命令从packet数组复制到thd->query成员变量
–>mysql_parse() 将控制权交给词法解析器Lex,把查询命令传递给查询优化器
–>query_cache_send_result_to_client() 查询缓存
–>yyparse()
–>mysql_execute_command()
–>query_cache_end_of_result()
网络连接监听
handle_connections_socket() 负责实现监听器,本质上是一个无限循环,循环等待来自客户端的连接,为监听到的每一个连接分配一个处理的线程。循环退出条件是变量abort_loop被设置为TRUE。在探测到一个连接后,会调用create_new_thread()函数创建一个新的线程。THD类负责保存和管理与线程有关的所有信息。
handle_connections_socket()函数:
create_new_thread()函数如下:
线程池处理请求
create_new_thread()内部,首先会执行start_cached_thread()函数,它试图从连接池中寻找一个现有的线程来重复使用。
首先创建线程的时候,会从线程池中取,若取完了,则新建一个线程。然后控制权转到了handler_one_connection()函数。
handler_one_connection()函数负责识别查询命令,然后交给do_command处理。
do_command调用Socket读取到查询命令,然后通过dispatch_command()函数把查询命令传递到解析器。
handler_one_connection()函数:
查询解析器
查询解析器是用Lex和YACC建立的。
Lex用来识别各种记号,常数和语法。
YACC用来生成与Mysql源代码交互的代码。
查询解析器将SQL命令分解成一系列基本元素,存入一个内部查询结构,再把查询命令传递给一个名为mysql_execute_command()的命令处理器。
查询优化器
进入查询优化器子系统后,在join->prepare()和join->optimize()函数对查询的执行过程进行优化之后,join->optimeize()函数将开始实际执行这个查询,即控制权将呗转给底层的do_select()函数以具体完成选取和投影操作。
查询执行
最后,sub_select()函数将调用某个存储引擎去读取并处理元祖,然后把结果返回给客户。在查询结果被写到网络之后,控制权将返回到handler_connections_sockets()循环。