MySQL 的 SQL 查询执行流程

前一篇内容结合了编译器了解了 SQL engine 的一些知识。

这里具体介绍 Expression 在 MySQL 是如何编译执行的,即 query 的衡量,评估,执行是如何实现的。

首先简单介绍一下 MySQL 中的 Expression 的含义是什么?

1 MySQL 中的表达式

在 MySQL 中,表达式 (expression)是一系列算子,数值,函数的集合。一般可以在一个查询语句的三个位置找到:

  • 在 SELECT 语句的 projection list,SELECT 真正查询的 column 列表
  • WHERE 语句的 selection list,where 中的用来过滤的 column 列表
  • HAVING 语句的 aggregated selection。Having 中的聚集列表

2 和 3 主要是 filter expression,通常由算数,比较算子构成。

除此之外,还有 Join 条件,group 条件,order by 条件,limit 语句中也会包含 expression。


在 MySQL 中,这些 expression 在代码中是以树形的继承类 Item 表示。Item类很重要。是整个语句操作对象的基类,用于表示 expression 的不同组件,例如逻辑操作符、算术操作符、常量值、字段引用等等都是一个 item。例如整数使用 Item_int 表示,表示 SQL 中某个整数的常量值。相等运算符(=)使用 Item_func_eq 表示,可以计算其他两个 Item 的相等性。

根据这些类的性质,可以以 Item 的树形式构造所有类型的表达式,其中根节点的 Item 表示完整的表达式, 叶节点是涉及到的算子。如下图用 Item 表示了表达式 “age = 26 AND name = ’Peter’”。

为了衡量和执行 Item tree 表示的 expression,每个 Item 类实现了一系列的虚函数来计算 Item 的值。最值得注意的是 val_int() 方法,返回被衡量 Item 的 64 位 int 值。事实上,对于最基本的类型,都存在一组val_方法,它们计算给定类型 expression 的求值。

例如,Item_func_eq 的 val_int() 方法计算树中另外两个子 item 的相等性, 其中要比较的算子是通过调用子 item 的 val_int () 方法提取的。

MySQL 对于支持的数据类型 和 SQL 函数,都有一个 Item 派生类。从大量的 Item 派生类中,有几个派生类是比较重要的:

  • Item_int::表示 expression 中的常量整数。
  • Item_string:表示 expression 中的常量字符串。
  • Item_field:表示 table 中的一个 column,对于给定的行,val_() 函数返回 column 类型对应的值。
  • Item_func_eq:表示 = 算子
  • Item_func_gt:表示 > 算子
  • Item_cond_and:表示逻辑运算 AND 算子
  • Item_cond_or:表示逻辑运算 OR 算子

2 MySQL 中 Query 的生命周期

为了了解 expression 在 MySQL 是怎么执行的,主要是看 query 在 MySQL 中的生命周期:parsing,preparing,optimizing 和 execution。下图是 MySQL 查询引擎的生命周期,每个组件的输入和输出,到最后怎么拿到真实的存储引擎的数据:数据流动过程是从 SQL statement 到 Query_block 到 AccessPath,到 Iterators,再到存储引擎。

parser

当数据库从客户端接收 SQL 查询并将查询发送给 parser 时,查询的生命周期就开始了。首先是 lexical scanner (词法扫描),将整个 SQL 语句解析成 token 流,如 “SELECT count(*), state FROM customer GROUP BY state” 解析成了一个个 token

• SELECT • count • ( • * • ) • , • state • FROM • customer • GROUP • BY • state