函数间关系的主要逻辑如下:
handle_select(){――第(1)层
mysql_union(); //处理union操作
mysql_select(){――第(2)层
JOIN::optimize() {――第(3)层
simplify_joins(); //把外连接简化为内连接
optimize_cond(…, conds, …); //优化whrer子句
optimize_cond(…, having, …); //优化having子句
opt_sum_query(); //优化count(*), min() and max(),只适用于没有group子句的情况
make_join_statistics();//确定多表的连接路径;单表是多表的特例
{――第(4)层
update_ref_and_keys();//获取索引信息,为快速定位数据、条件比较做准备
get_quick_record_count();
choose_plan()
{――第(5)层
optimize_straight_join();
find_best ();
greedy_search();
{――第(6)层
best_extension_by_limited_search()
{――第(7)层
best_access_path()//估算局部查询树的最佳访问路径
}
}//――第(6)层结束
}//――第(5)层结束
}//――第(4)层结束
……
make_outerjoin_info();//填充外连接的信息
……
substitute_for_best_equal_field(); //循环遍历所有表达式,化简表达式(重复的等式能去掉则直接去掉,如:WHERE a=5 AND ((a=b AND b=c) OR c>4) 的条件将变为:“=(a) and (=(5,a,b,c) or c>4)”)[1]
……
make_join_select(); //用于执行各种不同情况的join查询。该函数通过join时,连接表的不同搜索方式(唯一索引查找、ref查找、快速范围查找、合并索引查找、全表扫描等不同方式),进行join操作的处理
//优化distinct谓词相关的情况,如下多行代码,处理不同的distinct情况
……
//创建临时表
//处理简单的IN子查询
}――第(3)层结束,optimize()
}――第(2)层结束,mysql_select()
}――第(1)层结束,handle_select()
以上是查询优化的整体流程,在进入第4层之前是的逻辑查询计划生成,如外连接转换为內连接、表达式化简、子查询的消除等逻辑优化策略都是在这个阶段之前完成的。
第4层之后是物理查询计划生成,利用贪婪(greddy)算法,实现多个关系的访问方式确定(顺序访问、索引访问)、连接方式确定(嵌套循环连接算法)、连接顺序选取。
[1] 如执行如下sql,并查看其查询计划,可以看到查询计划的条件发生了变化:
create table t(a int, b int, c int, d int);
insert into t values(1,2,3,4);
insert into t values(5,5,5,5);
insert into t values(10,20,30,40);
explain EXTENDED select * from t WHERE a=5 AND ((a=b AND b=c) OR c>4);
SHOW WARNINGS;
查询计划的结果为:
select `test`.`t`.`a` AS `a`,`test`.`t`.`b` AS `b`,`test`.`t`.`c` AS `c`,`test`.`t`.`d` AS `d` from `test`.`t` where ((`test`.`t`.`a` = 5) and (((`test`.`t`.`b` = 5) and (`test`.`t`.`c` = 5)) or (`test`.`t`.`c` > 4)))