这里将介绍在执行查询过程中,MYSQL服务器将会做的一些操作。

语句解析器和预处理

MYSQL将通过语句解析器将SQL语句进行解析,生成一棵对应的“解析树”,MYSQL解析器将通过使用MYSQL语法规则和验证解析查询。

查询优化器

语法树被认为是合法后,由优化器将其转化成执行计划。一条查询可以有多种执行计划,这些不同的执行计划最后得出的结果都是相同的,查询优化器的作用就是在这些不同的执行计划之间找出最好的一种执行计划。
MSQL使用基于成本的优化器,它将预测一个查询使用某种执行计划的成本,并选择其中成本最小的执行优化器。
估计成本时,有很多种原因会导致成本预算出错,比如:

  • 统计信息不准确,查询优化器的依赖的统计信息来自于存储引擎,有一些存储引擎提供的统计信息并不准确,比如InnoDB提供的行数只是一个预估值
  • 执行从成本估算并不等于实际成本,例如当要查询一个很大的表,如果表中的数值都是顺序存储的,或者这些页已经在内存中的话,那么实际成本会很小而成本估算很大,MYSQL并不知道那些页在磁盘上那些页在内存中
  • MYSQL不考虑并发的情况
  • MYSQL不考虑不受控制的成本,如用户自定义函数和执行存储过程的成本
  • MYSQL也并不是任何时候都基于成本进行优化,有时也会按照固定规则,例如当有全文索引时,即使使用WHERE条件更快,MYSQL也会使用全文索引

MYSQL的查询优化器使用了很多策略来找出最优执行方式,这些优化策略可以简单的分为静态优化和动态优化。静态优化可以直接对解析树进行分析并优化,例如优化器可以将WHERE条件转换成另一种等价形式。静态优化不依赖于数值,如WHERE带入的常数,静态优化在第一次完成后就一直有效,即使数值不同也可以执行。动态优化则相反。

MYSQL如何执行关联查询

这里所说的关联比一般意义上的关联更为广泛,总的来说MYSQL认为任何一次查询都是关联,而不仅仅是一个查询需要匹配到两个表的操作才叫关联,在MYSQL中,每一个查询,每一个片段都可能是关联。
例如,当使用UNION查询,MYSQL先将一系列单个查询得到的数据放到的一个临时表中,然后再从临时表中读出数据来完成UNION查询。因为MYSQL对于关联的定义非常广泛,所以这里认为这个临时表也是一次关联。

MYSQL关联执行的策略

MYSQL对任何关联都执行嵌套循环关联操作,即MYSQL先在一个表中循环取出单条数据,然后再嵌套循环到下一个表中寻找匹配的行,依次下去,直到找到所有表中匹配的行为止。然后在根据找到的行返回查询中需要的各个列。

排序优化

当不能使用索引生成排序结果的时候,MYSQL需要自己进行排序,如果数据量小就在内存中排序,如果数据量大则需使用磁盘,MYSQL将这个操作称为文件排序。如果需要排序的数据量小于排序缓冲区,则在内存中进行快速排序操作,如果内存不够排序,那么MYSQL会先将数据分块,对每个独立的列使用快速排序,并将这些块的排序结果存放在磁盘上,然后将这些结果合并。
MYSQL使用单次传输排序的算法,这需要先查询所需要的所有列,然后再根据给定列进行排序,最后直接返回排序结果。这个算法只需要操作一次顺序IO读取所有数据,但如果需要返回的数据量非常多,会额外占用非常大的空间。