oracle 查询转换简单说明5

2023年 9月 12日 63.4k 0

1.1.1      Group-by 放置

Group-by放置(Group-by Placement)的目的基本上与非重复放置一样。唯一明显的差别是它们应用的查询类型不同。前者适用于包含GROUP BY子句的查询,后者适用于包含DISTINCT运算符的查询。Group-by放置是基于成本的查询转换,从11.1版本开始起才可用。

 

在下面这个来自group_by_placement.sql脚本的例子中,在两张表中存在父-子关系,且子表(t2)包含的记录数比父表(t1)更多:

SELECT t1.n, t2.n, count(*) FROM t1, t2
WHERE t1.id = t2.t1_id GROUP BY t1.n, t2.n;

 

当t2.n中不同值的数量远远小于子表中存储的数据行的数量时,group-by放置就产生了下面的查询。一个额外的GROUP BY子句被应用于子表的数据上,以便在连接父表之前消除重复。还要注意,在顶层查询的SELECT子句中,count函数被sum函数替换了:

SELECT t1.n, vw_gb.n sum(vw_gb.cnt)

FROM t1, (select t2.t1_id,t2.n,count(*) as
cnt from t2 group by t2.t1_id,t2.n) vw_gb

WHERE t1.id = vw_gb.t1_id

group by t1.n, vw_gb.n;

 

1.1.1      Order-By 消除

Order-By消除(Order-By Elimination)的目的是从子查询、内联视图以及常规视图中移除不必要的ORDERBY子句。很显然这种基于启发式的查询转换不会考虑顶层SELECT子句。当一个ORDER BY后面跟随一个不保证会按顺序返回数据的操作时,或者跟随一个会按照不同顺序返回数据的操作时,就可以认为这个ORDER BY子句是没有必要的;例如,后面跟随另一个ORDER BY或者聚合。

 

在下面这个来自order_by_elimination.sql脚本的例子中,不仅内联视图中有一个ORDER BY,而且顶层查询块中还有一个GROUP BY:

SELECT n2,count(*)

FROM (SELECT n1,n2 FROM t ORDER BY n1)

GROUP BY n2;

 

因为顶层查询块中的GROUP
BY并不保证按顺序返回数据,所以order-by消除就会移除ORDER BY并产生以下查询:

SELECT n2,count(*)

FROM(SELECT n1,n2 FROM t)

GROUP BY n2;

 

查询优化器使用选择列表裁剪和简单视图合并进一步将查询转化成以下形式:

SELECT n2,count(*) FROM t GROUP BY n2;

 

1.1.1      子查询展开

子查询展开(Subquery
Unnesting)的目的是将半连接(IN,EXISTS)、反连接(NOT IN,NOT EXISTS)以及标量子查询注入到查询块包含的FROM子句中去,并将它们转化为内联视图。一些展开是由基于启发式的查询转换执行的,另外一些则是由基于成本的查询转换实施的。

 

应用这种查询转换的主要原因是启用所有可能的连接方法。事实上,如果没有子查询展开,子查询可能就不得不在包含它的查询块每返回一行数据时都执行一遍。然而子查询展开也并非总能执行。例如,如果子查询中包含某种类型的聚合或者包含rownum伪列,展开都不可能执行。当半连接和反连接子查询中含有集合运算符时,只有从11.2版本开始才可以展开。此外,从12.1版本开始,标量子查询展开改进为在SELECT子句中处理标量子查询。

 

下面的例子来自subquery_unnesting.sql脚本,演示了这种查询转换是如何工作的:

SELECT * FROM t1

WHERE EXISTS(SELECT 1 FROM t2 WHERE t2.id
=t1.id AND t2.pad IS NOT NULL);

 

子查询展开可以归纳为两个步骤。第一步,如下面的查询所示,重写子查询为内联视图。注意,下面展示的并不是合法的SQL语句,因为实现半连接的运算符(s=)
在SQL语法中并不可用(只在SQL引擎内部使用):

SELECT *

FROM t1,(SELECT id FROM t2 WHERE pad IS NOT
NULL) sq

WHERE t1.id s= sq.id;

 

第二步,正如此处展示的,将内联视图重写为正常的连接:

SELECT t1.*

FROM 
t1,t2

WHERE t1.id s= t2.id AND t2.pad IS NOT
NULL;

 

尽管前面的例子是基于半连接的,这个查询转换同样适用于反连接。唯一的区别是使用反连接运算符(a=),而不是半连接运算符(s=)。 这是另外一个SQL引擎仅在内部使用的运算符。

 

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论