1.1.1 选择列表裁剪
选择列表裁剪(Select
List Pruning)的目的是移除不必要的列或者移除来自子查询、内联视图以及普通视图的SELECT子句的表达式。这种类型的查询转换不会考虑顶层查询的SELECT子句。当一个列或者表达式没有在除引用或定义它的SELECT子句以外的地方被引用时,就会被认为是没有必要的。这是一种基于启发式的查询转换。
在下面这个来自select_list_pruning.sql脚本的例子中,注意,子查询引用的两个列(n2和n3)没有被外层的主查询引用:
SELECT n1
FROM(SELECT n1,n2,n3 FROM t);
因为n2和n3这两个列是没有必要的,选择列表裁剪会移除它们并产生以下查询:
SELECT n1
FROM (SELECT n1 FROM t);
使用视图合并,可以进一步简化查询。于是生成了下面这样的查询:
SELECT n1 FROM t;
1.1.1 谓词下推
谓词下推(Predicate
Push Down)的目的是将谓词下推到无法合并的视图或内联视图的内部。能够进行下推的谓词必须包含在拥有不可合并的视图或内联视图的查询块的内部。应用这种类型的查询转换有三个主要的原因:
Ø 为了启用额外的访问路径(典型的是索引扫描);
Ø 为了启用额外的连接方法以及连接顺序;
Ø 为了确保能够尽可能快地应用谓词,从而避免不必要的处理操作。
谓词下推有两个子范畴:过滤谓词下推和连接谓词下推。两种变换的不同是由它们操作的谓词的类型决定的。
1.过滤谓词下推
过滤谓词下推 (Filter
Push Down)的目的是将限制条件(过滤条件)下推到不可合并的视图或者内联视图的内部。这是一种基于启发式的查询转换。注意,这种查询转换不下推连接条件。下推连接条件是由下一节呈现的查询转换完成的。
下面的例子来自filter_push_down.sql脚本。UNION集合运算符用来防止内联视图与顶层查询合并:
SELECT *
FROM (SELECT * FROM t1 UNION SELECT * FROM
t2) WHERE id=1;
过滤谓词下推将限制条件(id=1)下推到内联视图的内部并产生了下面的查询。现在,这两张表不仅可以通过索引来访问,同时也保证了UNION集合运算符需要的排序操作所处理的记录尽可能少:
SELECT *
FROM (
SELECT * FROM t1 WHERE id=1
UNION
SELECT * FROM t2 WHERE id=1);
此外简单视图合并还消除了顶层查询块。
2.连接谓词下推
连接谓词下推(Join
Predicate Push Down)的目的是将连接谓词下推到无法合并的视图或内联视图的内部。这是一种基于成本的查询转换。
下面的例子来自join_predicate_push_down.sql脚本。UNION集合运算符用来防止内联视图与顶层查询合并。注意,内联视图与上一节例子中所用的是一样的(尽管表的名称不一样)。只不过在本例中,内联视图与另外一张表进行连接:
SELECT * FROM t1, (SELECT * FROM t2 UNION
SELECT * FROM t3) t23 WHERE t1.id = t23.id;
连接谓词下推将连接条件(t1.id=t23.id)下推到内联视图的内部并产生以下查询。这个查询享有与上一小节描述的查询相同的好处(启用了索引访问,减少了需要排序的数据总量)。在这个例子中,额外的访问路径也允许查询优化器自由选择所有可用的连接方法和连接顺序:
SELECT * FROM t1, (SELECT * FROM t2 WHERE
t2.id = t1.id UNION SELECT * FROM t3 WHERE t3.id = t1.id) t23;
尽管前面的SQL语句并不是有效的(t1.id列在内联视图内部并不可见),但是SQL引擎可以处理与它类似的一些情况。为了支持这样的查询,从12.1版本开始可以使用侧向内联视图。例如,下面的查询在12.1版本中是合法的:
SELECT * FROM t1, lateral(SELECT * FROM t2
WHERE t2.id = t1.id UNION SELECT * FROM t3 WHERE t3.id = t1.id) t23;