1.1.1 谓词迁移
谓词迁移(Predicate
Move Around)的目的是将限制条件(过滤条件)提取、跨越、下推到无法合并的视图或内联视图的内部。尽管这有点类似谓词下推,这个查询转换还能将谓词在彼此不包含的查询块之间移动。应用这种基于启发式的查询转换的主要原因是启用额外的访问路径(一般来说是索引扫描)并确保谓词能够尽可能快地应用。
下面例子中的两个内联视图来自predicate_move_around.sql脚本,因为DISTINCT运算符的原因不能与顶层查询合并。第一个内联视图在用于两个内联视图连接条件(t1.n=t2.n)的列(n)上有一个限制条件:
SELECT t1.pad, t2.pad
FROM (SELECT DISTINCT n, pad FROM t1 WHERE
n = 1) t1,
(SELECT DISTINCT n, pad FROM t2) t2
WHERE t1.n = t2.n;
在本例中,谓词迁移执行以下三个主要步骤。
(1)将限制条件(n=1)从第一个内联视图中提取到顶层查询中。
(2)在限制条件(t1.n=1)与连接条件(t1.n=t2.n)之间应用传递特性,从而产生新的谓词(t2.n=1)。
(3)将新的谓词下推到第二个内联视图内部。
结果就是谓词迁移生成了接下来的查询语句。将谓词添加到第二个内联视图内部,不仅允许通过索引访问t2表,而且也相应地减少了DISTINCT运算符需要处理的数据总量:
SELECT t1.pad, t2.pad
FROM (SELECT DISTINCT n, pad FROM t1 WHERE
n = 1) t1,
(SELECT DISTINCT n, pad FROM t2 WHERE n = 1) t2
WHERE t1.n = t2.n;
1.1.1 非重复放置
非重复放置(Distinct
Placement)的目的是尽快消除重复。这种基于成本的查询转换仅从11.2版本开始起才可用。
DISTINCT运算符的作用是从结果集中去除重复。当它在查询中与其他一个或多个联接一同被指定时,从概念上讲,数据库引擎应该在联接处理完毕后再处理DISTINCT运算符。然而,要达到最佳性能,在某些情况下需要在处理联接之前消除重复。更早消除重复可以保证中间结果集尽可能小,这样需要联接处理的数据也随之减少了。
下面的例子来自distinct_placement.sql脚本,在两张表中存在着父-子关系。进一步来说,你可以假设子表(t2)比父表(t1)包含更多的记录:
SELECT DISTINCT t1.n, t2.n FROM t1, t2
WHERE t1.id = t2.t1_id;
当t2.n的不同值的数量远远少于子表中存储的数量时,非重复放置就产生了下面的查询。注意额外增加的DISTINCT运算符,它应用于子表的数据,在联接父表之前就消除了重复:
SELECT DISTINCT t1.n, vw_dtp.n FROM t1,
(select DISTINCT t2.t1_id,t2.n from t2)
vw_dtp
WHERE t1.id = vw_dtp.t1_id;
1.1.1 非重复消除
从10.2.0.4版本开始可用的非重复消除(Distinct Elimination)的目的,是移除对于保证结果集不包含重复数据来说不需要的DISTINCT运算符。这是一种基于启发式的查询转换,可以在SELECT子句涉及以下情况时使用,在不修改要查询的列的情况下,查询所有的主键列、所有非空的唯一键列或rowid。
下面的例子来自distinct_elimination.sql脚本。注意,表的主键定义在名为id的列上:
SELECT DISTINCT id,n FROM t;
由于id列的出现,也就是表的主键,在SELECT子句中就足以保证数据行的唯一性。于是,非重复消除产生了以下查询:
SELECT id,n FROM t;