一 背景和架构
我们都知道,利用编写程序来动态实现我们应用所需要的逻辑,从而程序执行时得到我们需要的结果。那么数据库就是一种通过输入SQL字符串来快速获取数据的应用。当然,假设没有数据库这种系统应用,用程序如何实现呢?我们可能会发现,即使不管数据如何存储、数据是否并发访问,仍然需要不断通过修改程序处理不同应用对数据的不同请求。比如大数据领域,我们通常通过非关系型数据库的API,实现对数据的获取。然而这种方式虽然入门简单,但是维护极难,而且通用性不强,即使不断进行软件架构设计或者抽象重构,仍然需要不断地变换应用,这也是为何非关系型数据库回头拥抱数据库SQL优化器的原因。
SQL优化器本质上是一种高度抽象化的数据接口的实现,经过该设计,客户可以使用更通用且易于理解的SQL语言,对数据进行操作和处理,而不需要关注和抽象自己的数据接口,极大地解放了客户的应用程序。
本文就来通过图形解说的方式介绍下MySQL 8.0 SQL优化器如何把一个简单的字符串(SQL),变成数据库执行器可以理解的执行序列,最终将数据返还给客户。强大的优化器是不需要客户关注SQL如何写的更好来更快获得需要的数据,因此优化器对原始SQL一定会做一些等价的变化。在《MySQL 8.0 Server层最新架构详解》一文中我们重点介绍了MySQL最新版本关于Server层解析器、优化器和执行器的总体介绍,包括一些代码结构和变化的详细展示,并且通过simple_joins函数抛砖引玉展示了MySQL优化器在逻辑变换中如何简化嵌套Join的优化。本文我们会一步一步带你进入神奇的优化器细节,详细了解优化器优化部分的每个步骤如何改变着一个SQL最终的执行。
本文基于最新MySQL8.0.25版本,因为优化器转换部分篇幅比较长,我们分成两篇文章来介绍,第一部分介绍基于基本结构的Setup和Resolve的解析转换过程,第二部分介绍更为复杂的子查询、分区表和连接的复杂转换过程,大纲如下:
Setup and Resolve
- setup_tables : Set up table leaves in the query block based on list of tables.
- resolve_placeholder_tables/merge_derived/setup_table_function/setup_materialized_derived : Resolve derived table, view or table function references in query block.
- setup_natural_join_row_types : Compute and store the row types of the top-most NATURAL/USING joins.
- setup_wild : Expand all '*' in list of expressions with the matching column references.
- setup_base_ref_items : Set query_block's base_ref_items.
- setup_fields : Check that all given fields exists and fill struct with current data.
- setup_conds : Resolve WHERE condition and join conditions.
- setup_group : Resolve and set up the GROUP BY list.
- m_having_cond->fix_fields : Setup the HAVING clause.
- resolve_rollup : Resolve items in SELECT list and ORDER BY list for rollup processing.
- resolve_rollup_item : Resolve an item (and its tree) for rollup processing by replacing items matching grouped expressions with Item_rollup_group_items and updating properties (m_nullable, PROP_ROLLUP_FIELD). Also check any GROUPING function for incorrect column.
- setup_order : Set up the ORDER BY clause.
- resolve_limits : Resolve OFFSET and LIMIT clauses.
- Window::setup_windows1: Set up windows after setup_order() and before setup_order_final().
- setup_order_final: Do final setup of ORDER BY clause, after the query block is fully resolved.
- setup_ftfuncs : Setup full-text functions after resolving HAVING.
- resolve_rollup_wfs : Replace group by field references inside window functions with references in the presence of ROLLUP.
二 详细转换过程
转换的整个框架是由Query_expression到Query_block调用prepare函数(sql/http://sql_resolver.cc)并且根据不同转换规则的要求自顶向下或者自底向上的过程。
图片
1 传递null到join的内表列表(propagate_nullability)
prepare开始先要处理nullable table,它指的是table可能包含全为null的row,根据JOIN关系(top_join_list)null row可以被传播。如果能确定一个table为nullable会使得一些优化退化,比如access method不能为EQ_REF、outer join不能优化为inner join等。
2 解析设置查询块的leave_tables(setup_tables