本文解决了什么问题:希望通过这些文章能够帮你更加顺畅的理解mysql优化器的行为;在你阅读mysql源代码之前了解更多的背后思路。
本文不解决什么问题:教你如何读懂源代码;
这个系列很长,大概按这样的思路进行下去: 基本的数据结构、语法解析、join的主要算法、join顺序和单表访问。数据结构(以及他们的关系)和算法流程总是相互穿插介绍。
建议阅读:参考文献中的文章和书籍,都建议在阅读本文之前阅读。
mysql语法解析封装在函数mysqlparser中完成。跟其他的语法解析器一样,它包含两个模块:词法分析(lexical scanner)和语法规则(grammar rule module)。词法分析将整个sql语句打碎成一个个单词(token),而语法规则模块则根据mysql定义的语法规则生成对应的数据结构,并存储在对象thd->lex结构当中。最后优化器,根据这里的数据,生成执行计划,再调用存储引擎接口执行。
词法分析和语法规则模块有两个较成熟的开源工具flex和bison分别用来解决这两个问题。mysql处于性能和灵活考虑,选择了自己完成词法解析部分,语法规则部分使用bison。词法解析和bison沟通的核心函数是由词法解析器提供的函数接口yylex(),在bison中,必要的时候调用yylex()获得词法解析的数据,完成自己的语法解析。bison的入口时yyparse(),在mysql中是,mysqlparse。
如果对词法分析和语法规则模块感到陌生,建议阅读参考文献[4][5][6]先注1,否则很难理解整个架构,或者至少会有很强的断层感。而且,根据bison的action追踪mysql数据的存储结构是很有效的。
简单的解析过程可以使用下面的示意图说明:

具体的解析一个sql语句的where部分:
bison在做语法解析后,会将解析结果(一颗解析树/ast)存储在thd::lex中。这里将通过考察存储where的数据结构来查看语法解析的结果。
在了解mysql的解析树之前,我们需要先来认识一个重要的数据结构item。这是一个基础对象,在优化器部分代码,满地都是。在mysql internal manual中也单独介绍:the item class。
item是一个基础类,在他的基础上派生了很多子孙。这些子类基本描述所有sql语句中的对象,他们包括:
一个文本字符串/数值对象
一个数据表的某一列(例如,select c1,c2 from dual...中的c1,c2)
一个比较动作,例如c1>10
一个where子句的所有信息
......
可以看到,item基本上代码sql语句中的所有对象。在语法解析树中,这些item以一颗树的形式存在。示意图如下:
从select子句开始,我们看到对应的where_clause就是我们关注的where:
我们来看看bison中的几个重要的action参考注1:
根据这里的bison语法,就可以生产上面的where语法树了。如果你是和我一样刚刚了解flex/bison/ast,一定也会决定很巧妙!
绘制了下面的关系图用来描述where和where解析树的各个分支:
例如where条件where c1="orczhou" and c2 > 10,where本身(lex->select->where)就是一个item_cond_and对象,这个对象中有一个item list,将list中每一个item的值做and运输,也就是这个where的取值了。
这里,where的list中有两个item对象,分别代表了c1="orczhou"和c2 > 10。具体的,这两个对象的类型分别是item_func_eq和item_func_gt。
再单独看看item_func_gt(代表c2 > 10)对象,这个对象由item_func派生而来(当然追根朔源都是item的孩儿们),这个对象有成员:item **args。args则存放了比较操作需要使用的item。
对于c2 > 10,这个不等式中有两个item,分别代表字段c2和整数10,存储这两个对象的类型分别是:item_field和item_int。
where条件是:where id = 531389273 and reg_date > '2012-02-12 09';
打印where中的list
因为where有两个判断,所以这里list中有两个元素。
打印list中的第一个判断(id = 531389273)
这里等于操作有两个操作元素(arg_count=2),并以数组的形式存储在args中
打印上面等式的第一个对象(也就是id)
</blockquote>
可以看到这里的id对象的类型是item::field_item,也就是item_field类型。
继续从存储where的item_cond_and对象开始:
(点击可以查看大图)
看到item_cond_and的继承关系:item_cond->item_bool_func->......->item_result_filed->item
item一个很重要的成员函数就是type,所以在gdb的时候如果不清楚item的类型,可以调用该方法确定:
这篇文章就到这吧,希望能够继续下去。