开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 1531|回复: 1
打印 上一主题 下一主题
收起左侧

[Mysql] 探索MySQL源代码之SQL历险记

[复制链接]

跳转到指定楼层
楼主
发表于 2013-2-4 12:47:34 | 只看该作者 回帖奖励 |正序浏览 |阅读模式   广东省汕尾市
本文从一个select语句的执行过程出发,遍历MySQL的多个几子系统。
先放图一张, 按图索骥开始我们的历险.
当客户端连接上MySQL服务端之后,发出请求之前,服务端的线程是阻塞在do_command(sql/parse.cc)里的my_net_read函数中(就是socket里的read).
当客户端键入sql语句(本文例子select * from zzz)发送到服务端之后, my_net_read返回, 并从tcpbuffer中读取数据写入到packet这个字符串.
  • packet_length= my_net_read(net);
packet的第一个字节是个标志位, 决定数据包是查询还是命令,成功,或者出错。
接下来就进入dispatch_command(sql/sql/parse.cc)这个函数, 数据类型不再需要.
  • return_value= dispatch_command(command, thd, packet+1, (uint) (packet_length-1));
进入dispatch_command, 我们可见
  • 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(^_^),
  • #define yyparse MYSQLparse
是的开始解析sql了. 关于词法分析和语法匹配简单说几下.
对于一条像select * from zzz的语句首先进入词法分析,找到2个token(select, from), 然后根据token进行语法匹配, 规则在sql/yacc.yy里, 我把几个匹配到的pattern和action贴出来.

    select:
  • select_init
    {
  • LEX *lex= Lex;
    lex->sql_command= SQLCOM_SELECT;
  • }
    ;
  • /* Need select_init2 for subselects. */
    select_init:
  • SELECT_SYM select_init2
    | '(' select_paren ')' union_opt
  • ;
    select_paren:
  • SELECT_SYM select_part2
    {
  • LEX *lex= Lex;
    SELECT_LEX * sel= lex->current_select;
  • .....
    select_from:
  • FROM join_table_list where_clause group_clause having_clause
    opt_order_clause opt_limit_clause procedure_clause
  • {
    Select->context.table_list=
  • Select->context.first_name_resolution_table=
    (TABLE_LIST *) Select->table_list.first;
  • }
    ....
  • select_item_list:
    select_item_list ',' select_item
  • | select_item
    | '*'
  • {
    THD *thd= YYTHD;
  • Item *item= new (thd->mem_root)
    Item_field(&thd->lex->current_select->context,
  • NULL, NULL, "*");
    if (item == NULL)
  • MYSQL_YYABORT;
    if (add_item_to_list(thd, item))
  • MYSQL_YYABORT;
    (thd->lex->current_select->with_wild)++;
  • }
    ;
  • select_item:
    remember_name select_item2 remember_end select_alias
  • {
    THD *thd= YYTHD;
  • DBUG_ASSERT($1 < $3);
    if (add_item_to_list(thd, $2))
  • MYSQL_YYABORT;
    if ($4.str)
  • ...
可以看到action里最关键的就是add_item_to_list 和table_list的赋值.
解析后对于需要查询的表(zzz)和字段(*)这些信息都写入到thd->lex这个结构体里了.
例如其中thd->lex->query_tables就是表(zzz)的状况, thd->lex->current_select->with_wild 是表示该语句是否使用了*等等.

    (gdb) p *thd->lex->query_tables
  • $7 = {next_local = 0x0, next_global = 0x0, prev_global = 0x855a458, db = 0x85a16b8 "test", alias = 0x85a16e0 "zzz",
  • 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个步骤, 优化细节不表.

    if (!(join= new JOIN(thd, fields, select_options, result)))
  • ...
    if ((err= join->optimize()))
  • ...
  • join->exec();
结束了优化,我们要具体执行join->exec(),该函数实际进入的是JOIN::exec()(sql_select.cc)。
exec()首先向客户端发送字段title的函数send_fields, 没数据但字段也是要的。
然后再进入do_select(),根据表的存储引擎跳入到引擎具体的实现(zzz是myisam表)。
这里mi_scan就是myisam引擎扫描文件的函数,再看到

    (gdb) p info->filename
  • ./test/zzz
这不就是zzz表对应的物理文件吗。
通过一系列的mi函数访问磁盘拿到数据之后,会通过send_data发送数据给client,并从dispatch_command返回.最后在net_end_statement结束整个sql。
一个简单的select语句背后的执行过程是非常复杂的,上面的步骤都只是点到就止。
ps: 在sql_yacc.yy可见MySQL对于Oracle中常用的dual表的嘲讽。

结帖率:37% (7/19)
沙发
发表于 2013-2-12 10:31:31 | 只看该作者   北京市北京市
这个还给了解诶下
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:[email protected]
网站简介:精易论坛成立于2009年,是一个程序设计学习交流技术论坛,隶属于揭阳市揭东区精易科技有限公司所有。
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表