探索MySQL源代码之SQL历险记

本文从一个select语句的执行过程出发,遍历MySQL的多个几子系统。

成都创新互联公司专注于中大型企业的成都做网站、网站制作和网站改版、网站营销服务,追求商业策划与数据分析、创意艺术与技术开发的融合,累计客户数千家,服务满意度达97%。帮助广大客户顺利对接上互联网浪潮,准确优选出符合自己需要的互联网运用,我们将一直专注品牌网站制作和互联网程序开发,在前进的路上,与客户一起成长!

先放图一张, 按图索骥开始我们的历险.

当客户端连接上MySQL服务端之后,发出请求之前,服务端的线程是阻塞在do_command(sql/parse.cc)里的my_net_read函数中(就是socket里的read).

当客户端键入sql语句(本文例子select * from zzz)发送到服务端之后, my_net_read返回, 并从tcpbuffer中读取数据写入到packet这个字符串.

 
 
 
  1. packet_length= my_net_read(net); 

packet的第一个字节是个标志位, 决定数据包是查询还是命令,成功,或者出错。

接下来就进入dispatch_command(sql/sql/parse.cc)这个函数, 数据类型不再需要.

 
 
 
  1. return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1)); 

进入dispatch_command, 我们可见

 
 
 
  1. statistic_increment(thd->status_var.questions, &LOCK_status); 

这个就是show status questions的值累加.

接下的mysql_parse(sql/sql_parse.cc), 该函数是sql语句解析的总路口.

进入该函数后首先碰到的是query_cache_send_result_to_client,故名思义这个函数是在QCache里查询是否有相同的语句, 有则立即从QCache返回结果, 于是整个sql就结束了.

QCache里不存在的sql则继续前进来到parse_sql(sql/sql_parse.cc),这个函数主要就是调用了MYSQLparse. 而MYSQLparse其实就是bison/yacc里的yyparse(^_^),

 
 
 
  1. #define yyparse MYSQLparse 

是的开始解析sql了. 关于词法分析和语法匹配简单说几下.

对于一条像select * from zzz的语句首先进入词法分析,找到2个token(select, from), 然后根据token进行语法匹配, 规则在sql/yacc.yy里, 我把几个匹配到的pattern和action贴出来.

 
 
 
  1. select: 
  2. select_init 
  3. LEX *lex= Lex; 
  4. lex->sql_command= SQLCOM_SELECT; 
  5. /* Need select_init2 for subselects. */ 
  6. select_init: 
  7. SELECT_SYM select_init2 
  8. | '(' select_paren ')' union_opt 
  9. select_paren: 
  10. SELECT_SYM select_part2 
  11. LEX *lex= Lex; 
  12. SELECT_LEX * sel= lex->current_select; 
  13. ..... 
  14. select_from: 
  15. FROM join_table_list where_clause group_clause having_clause 
  16. opt_order_clause opt_limit_clause procedure_clause 
  17. Select->context.table_list= 
  18. Select->context.first_name_resolution_table= 
  19. (TABLE_LIST *) Select->table_list.first; 
  20. .... 
  21. select_item_list: 
  22. select_item_list ',' select_item 
  23. | select_item 
  24. | '*' 
  25. THD *thd= YYTHD; 
  26. Item *item= new (thd->mem_root) 
  27. Item_field(&thd->lex->current_select->context, 
  28. NULL, NULL, "*"); 
  29. if (item == NULL) 
  30. MYSQL_YYABORT; 
  31. if (add_item_to_list(thd, item)) 
  32. MYSQL_YYABORT; 
  33. (thd->lex->current_select->with_wild)++; 
  34. select_item: 
  35. remember_name select_item2 remember_end select_alias 
  36. THD *thd= YYTHD; 
  37. DBUG_ASSERT($1 < $3); 
  38. if (add_item_to_list(thd, $2)) 
  39. MYSQL_YYABORT; 
  40. if ($4.str) 
  41. ... 

可以看到action里最关键的就是add_item_to_list 和table_list的赋值.

解析后对于需要查询的表(zzz)和字段(*)这些信息都写入到thd->lex这个结构体里了.

例如其中thd->lex->query_tables就是表(zzz)的状况, thd->lex->current_select->with_wild 是表示该语句是否使用了*等等.

 
 
 
  1. (gdb) p *thd->lex->query_tables 
  2.   $7 = {next_local = 0x0, next_global = 0x0, prev_global = 0x855a458, db = 0x85a16b8 "test", alias = 0x85a16e0 "zzz", 
  3.   table_name = 0x85a16c0 "zzz", schema_table_name = 0x0, option = 0x0, on_expr = 0x0, prep_on_expr = 0x0, cond_equal = 0x0, 

sql解析完了, 优化呢? 别急接着往下看.

接着进入mysql_execute_command函数,这个函数是所有sql命令的总入口.

由于是这个sql是一个select, 于是execute_sqlcom_select就是我们下个要执行的函数,又然后进入了mysql_select(^_^怒了如此复杂).

mysql_select 就是优化器的模块, 这个模块代码比较复杂. 我们可以清楚看到创建优化器,优化,执行的3个步骤, 优化细节不表.

 
 
 
  1. if (!(join= new JOIN(thd, fields, select_options, result))) 
  2. ... 
  3. if ((err= join->optimize())) 
  4. ... 
  5. join->exec(); 

结束了优化,我们要具体执行join->exec(),该函数实际进入的是JOIN::exec()(sql_select.cc)。

exec()首先向客户端发送字段title的函数send_fields, 没数据但字段也是要的。

然后再进入do_select(),根据表的存储引擎跳入到引擎具体的实现(zzz是myisam表)。

这里mi_scan就是myisam引擎扫描文件的函数,再看到

 
 
 
  1. (gdb) p info->filename 
  2. ./test/zzz 

这不就是zzz表对应的物理文件吗。

通过一系列的mi函数访问磁盘拿到数据之后,会通过send_data发送数据给client,并从dispatch_command返回.最后在net_end_statement结束整个sql。

一个简单的select语句背后的执行过程是非常复杂的,上面的步骤都只是点到就止。

ps: 在sql_yacc.yy可见MySQL对于Oracle中常用的dual表的嘲讽。

【编辑推荐】

  1. 教你如何利用MySQL学习MongoDB
  2. Craigslist采用MongoDB替代MySQL
  3. MySQL中的NoSQL插件
  4. SQL与NoSQL——MySQL与NoSQL的融合
  5. 论MySQL何时使用索引,何时不使用索引

分享题目:探索MySQL源代码之SQL历险记
转载来于:http://www.mswzjz.cn/qtweb/news27/258377.html

攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能