一、概述

早期使用物化视图时,通常需要人工修改查询 SQL,显式在 SQL 中指定使用物化视图。支持自动查询修改功能后,物化视图自动查询改写功能将自动、透明的重写查询 SQL,使查询 SQL 可以使用物化视图(即使查询SQL本身指定的是查询基表而非物化视图),从而加速查询 SQL 的运行。

https://developer.aliyun.com/article/783672?spm=a2c6h.14164896.0.0.75b052840Ff9B1

二、查询改写检查

一个查询能被视图回答需要满足下面两个条件:

  1. 物化视图 Join 关系在查询中存在
  2. 物化视图有足够的数据来回答查询

部分条件下即使不满足条件,视图也可能会被用于改写。例如视图包含一部分查询所需要的数据,可以使用物化视图回答部分查询,剩下的数据从原始数据中计算。这部分改写检查会放在高级改写规则中进行介绍。

改写检查会依次进行 Join 检查和 Ouput 检查,如果查询或视图中含有 Grouping By 和 Aggregation,还会进行额外的检查,如果需要,会尝试对视图进一步聚合。

2.1. Join 检查

当查询和视图的表的 Join 关系相同时,视图才可能包含查询需要的所有的行和列。

  1. 一种简单的方式是只考虑没有子查询的 Inner Join,这时只用比较查询表和数量是否完全一致即可

  2. 通过一系列规则检查查询和视图的关系代数树包含的 Join 关系是等价的

  3. 构建 Join Graph

    构建 Join Graph 是更通用的一种方法。Join Graph 是一个以关系为结点,联接为边的图。Inner Join 的条件表示为无向边,Outer Join 的条件表示为有向边。Join Graph 由查询关系代数树构建而来,通过比较 Join Graph 就可以检查物化视图和查询包含相同的 Join 关系。

2.2. Output 检查

2.2.1. 等价关系

查询改写能够通过查询中的等价关系扩展改写的范围。因为等值条件具有传递性,等价关系可以从等值条件或者代数关系推导而来。例如可以从 A=date_format(now(), ‘%Y%m%D’) 和 B=date_format(now(), ‘%Y%m%D’),因为函数是确定性的,可以得到 A=B,如果我们还有 inner join 的条件 B=C,可以进一步得到 A=B=C。

可能会有某些其他的条件可以推导出等价关系,例如可以从 A=2,B=3,C=5 推导出 C = A + B。相比等值关系,寻找这种关系会使搜索过程更加复杂,而且我们无法实现所有的可能的相等关系,因此很少考虑这样的表达式。等价关系推导只搜索等值条件,即使可能错过一些改写机会,这样的浅层搜索可以保证速度。

2.2.2. 表达式

需要一种方法确定来自查询的表达式是否和视图中的表达式相等,或者能从中计算出来。表达式检查无法纯粹从语法上实现,两个表达式或者符号的文本相同,并不说明他们关系相等。例如别名的存在就会破坏基于语法的检查。

表达式检查需要通过等价关系和表的对应关系推导而来。如果视图和查询中所有的表都是唯一的,那么来自同一个表的列是等价的;如果视图和查询中有表出现多次,即 self join,那么查询到视图的表的映射就存在多种可能,每种可能都需要进行一次改写尝试。有了视图和查询之间列的对应关系和上一节的等价关系,通过代数系统确定来自查询的表达式是否和视图中的表达式相等,或者能否从中计算出来。

存在一些启发式的规则,允许一个表达式从另外的表达式中计算出来。比如算数规则从 x + 1 中计算出 x,例从 SUM(x) 和 COUNT(x) 计算出 AVG(x),还存在一些 Function Dependency 规则,例如时间函数,可以通过返回的天的结果计算年等。

2.2.3. Grouping 和 Aggregation 检查

三、改写规则

3.1. 基于语法的改写

文本匹配或者语法匹配是最简单的改写方法,将查询的文本与物化视图的文本或语法树进行比较,完全匹配可以进行改写。这种改写只能匹配完整的查询语句或子语句,细微的变化就会导致查询无法改写,适用的范围很小。基于语法的改写虽然简单,但是效率很高,改写的成本可以忽略不计。

3.2. 基于规则的改写

基于规则的改写和其他优化器规则相同,针对不同 Pattern 的查询和视图编写不同的规则,寻找等价的替代关系树。

最简单的一条规则就是直接比较子查询和视图的计划,如果相同就能改写。高级的改写规则不需要物化视图等同于被替换的计划,会尝试计算补偿谓词,构建等价查询表达式。

例如 Join 改写,比较 Join 查询的子表达式是否和视图 Join 的某个子表达相同或者能否从中计算出来,每一个 Join 子表达式都存在映射关系,最后检查补偿表达式能否从视图中计算得到。

基于规则的改写可以实现大量重写,实现也比较简单,改写匹配速度快,但是也存在局限性。这种改写依赖转换规则来寻找等价关系,因此需要穷举所有可能的转换关系来实现复杂视图的重写。一些复杂的视图不可能穷举所有的等价关系,例如存在很多的 Join 联接或者复杂的 Project 关系,基于规则的改写适用的范围取决于规则的数量。

3.3. 基于结构的改写

基于结构的改写与基于规则的改写相反,通过提取查询中的特征,使用一套规则进行匹配改写。优化器将查询表示为 SPJG 标准形式 (Join-Select-Project-GroupBy),提取查询中的 Join,Projects,Filters,Grouping 和 Aggregations 五种表达式,分别与物化视图对应的表达式进行匹配和改写。

这个方法是由微软在 2001 年 SIGMOD 论文《Optimizing queries using materialized views: A practical, scalable solution》系统化的提出。这种方法可以改写包含可以改写包含 Join,Filter,Project 的任意查询的方法,运用一系列的步骤匹配并得到补偿表达式。还可以进一步改写含有 Aggreagtion 的查询,在需要时添加 Aggregation 节点返回进一步汇总的结果。

基于结构的改写很容易扩展,例如改写 Outer Join 和子查询等,可以完成几乎全部的改写。但是搜索成本较高,尤其是在查询复杂,改写尝试次数很多的情况下。