数码资讯
oracle几个基本的查询转换详细解决方案
选购提示
关注价格、性能、续航、售后和真实使用场景,理性比较后再下单。
在实施计划的发展过程,并选择不同任务的转换;事实上,通过语法和查询中的权限检查,第一个被称为查询转换步骤,将有一系列的查询块的转换,那么优化器(最好是为了确定不同的计划选择的最终计算成本计划的最终方案)。
我们知道查询块是通过选择关键字来区分的。查询写的方式决定了查询块之间的关系。每个查询块通常嵌入在另一个查询块中或以某种方式连接。
复制代码代码如下所示:
选择*从员工那里department_id在(选择department_id部门)
它们是嵌套的查询块,但是它们的目的是探究如果查询改变了,是否提供了更好的查询计划。
查询转换步骤是完全透明的用户,可以说知道转换器可能不会改变对你的SQL语句的结构完全重写的情况下查询的结果,所以我们重新评估查询他们的心理预期是必要的,但这种转换总体上是好的,为了得到更有效的执行计划。
现在我们讨论几个基本的转换:
1。视图合并
2。子查询解决嵌套
三.谓词推进
4。物化视图查询重写
一、视图合并
这种方式很容易理解。它将把嵌入式视图扩展为独立的查询块,或者将查询的其余部分与一般的执行计划相结合。转换后的语句基本不包含视图。
视图合并通常发生在外部查询块的谓词包括:
1,可以在另一个查询块的索引中使用的列
2,可以在另一个查询块的分区截断中使用的列
3,可以限制连接视图中返回行数的条件
在这样的查询转换中,视图并不总是有自己的子查询计划,这是预先分析的,通常与查询的其他部分合并以获得性能改进。
复制代码代码如下所示:
SQL > AutoTrace traceonly解释
视图合并
从雇员A,
2(选择department_id员工)b_view
3在a.department_id = b_view.department_id(+)
4、a.salary > 3000;
执行计划
----------------------------------------------------------
计划哈希值:1634680537
----------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
----------------------------------------------------------------------------------------
| 0 | SELECT语句| | | 3161 222k | 3(0)| 00:00:01 |
1嵌套循环外| | | | | 3161 222k | 3(0)| 00:00:01 |
2表访问全|员工| * | | | | 103 7107 3(0)| 00:00:01 |
3索引范围扫描| * | | emp_department_ix | | | 31 93 0(0)| 00:00:01 |
----------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
2过滤器()。工资> > 3000
3 -访问(。department_id=department_id (+))
使用no_merge防止重写的意见
从雇员A,
2(选择 / * * / + no_merge department_id员工b_view)
3在a.department_id = b_view.department_id(+)
4、a.salary > 3000;
执行计划
----------------------------------------------------------
计划哈希值:1526679670
-----------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
-----------------------------------------------------------------------------------
| 0 | SELECT语句| | | 3161 253k | 7(15)| 00:00:01 |
1哈希连接右外| | * | | | 3161 253k | 7(15)| 00:00:01 |
| 2 |观| | | | 107 1391 3(0)| 00:00:01 |
3表访问全| | |员工| | | 107 321 3(0)| 00:00:01 |
4表访问全| * | |员工| | | 103 7107 3(0)| 00:00:01 |
-----------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1 -访问(。department_id=b_view 。department_id (+))
4过滤器()。工资> > 3000
在某些情况下,视图合并将被禁止或限制,如果一个查询块中使用的功能,分析聚合函数,并设置操作(如工会、相交、减),在通过的条款,任何一个,这是命令和行号;尽管如此,我们仍然可以使用 / * +合并(V)* /提示强制视图组合使用,但前提必须是确保返回的结果集是一致的!!!以下示例如下:
复制代码代码如下所示:
SQL >集AutoTrace
-使用聚合函数AVG导致视图合并失败
SQL >选择e1.last_name,e1.salary,v.avg_salary
2从hr.employees E1,
3(选择department_id,AVG(工资)avg_salary
4从hr.employees E2
5组department_id)V
6在e1.department_id = v.department_id和e1.salary > v.avg_salary;
执行计划
----------------------------------------------------------
计划哈希值:2695105989
----------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
----------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 17 697 8(25)| 00:00:01 |
|×1 |哈希连接| | | | 17 697 8(25)| 00:00:01 |
| 2 |观| | | | 11 286 4(25)| 00:00:01 |
3哈希组| | | | | | 11 77 4(25)| 00:00:01 |
4表访问全|员工| | | | | 107 749 3(0)| 00:00:01 |
5表访问全| | |员工| | | 107 1605 3(0)| 00:00:01 |
----------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1 -访问()。department_id=V。department_id )
筛选器(。工资>V。avg_salary )
合并使用(合并)
SQL >选择合并(V) / / * + e1.last_name,e1.salary,v.avg_salary
2从hr.employees E1,
3(选择department_id,AVG(工资)avg_salary
4从hr.employees E2
5组department_id)V
6在e1.department_id = v.department_id和e1.salary > v.avg_salary;
执行计划
----------------------------------------------------------
计划哈希值:3553954154
----------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
----------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 165 5610 8(25)| 00:00:01 |
|×1 |滤波器| | | | | |
2哈希组| | | | | | 165 5610 8(25)| 00:00:01 |
|×3 |哈希连接| | | 3296 109k | 7(15)| 00:00:01 |
4表访问全|员工| | | | | 107 2889 3(0)| 00:00:01 |
5表访问全|员工| | | | | 107 749 3(0)| 00:00:01 |
----------------------------------------------------------------------------------
二、子查询解决嵌套
最典型的方法是对表连接进行子查询。它与视图合并的主要区别在于它的子查询位于WHERE子句中,嵌套检测由转换器完成。
下面是一个子查询表连接示例:
复制代码代码如下所示:
SQL >选择employee_id,last_name,工资,department_id
2从hr.employees
3 department_id在哪里
4(选择department_id)
5从hr.departments哪里location_id > 1700);
执行计划
----------------------------------------------------------
计划哈希值:432925905
---------------------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
---------------------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 34 884 4(0)| 00:00:01 |
| 1 |嵌套循环| | | | | |
| 2 |嵌套循环| | | | 34 884 4(0)| 00:00:01 |
| 3表访问的索引rowid |部门| | | | 4 28 2(0)| 00:00:01 |
4索引范围扫描| * | | dept_location_ix | 4 | | 1(0)| 00:00:01 |
5索引范围扫描| * | | emp_department_ix | 10 | | 0(0)| 00:00:01 |
| 6表访问的索引rowid | |员工| | | 10 190 1(0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
4访问(location_id> 1700)
5访问(department_id=department_id )
使用 / * * / + no_unnest被迫分开的子查询执行计划生成
SQL >选择employee_id,last_name,工资,department_id
2从hr.employees
3 department_id在哪里
4(选择no_unnest * / / * + department_id
5从hr.departments哪里location_id > 1700);
执行计划
----------------------------------------------------------
计划哈希值:4233807898
--------------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
--------------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 10 190 14(0)| 00:00:01 |
|×1 |滤波器| | | | | |
2表访问全| | |员工| | | 107 2033 3(0)| 00:00:01 |
| * 3表访问的索引rowid |部门| | | | 1 7 1(0)| 00:00:01 |
4索引唯一扫描| * | | dept_id_pk | 1 | | 0(0)| 00:00:01 |
--------------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1过滤器(存在(选择 / * + no_unnest×0从人力资源部门。
部门,department_id=:B1和location_id> 1700))
3过滤器(location_id> 1700)
4访问(department_id=:B1)
你可以看到任何嵌套查询子查询的解决方案只使用滤波器两表,第一步的查询谓词的信息并没有变化,这意味着107排的雇员表中返回的每一行必须执行子查询。尽管在Oracle的子查询缓存优化我们不能判断两者的计划的缺点,但相比于嵌套循环,过滤操作的缺点是很明显的。
如果有相关的子查询,嵌套过程通常将相关子查询转换成非嵌套视图,然后与主查询中的表x连接,例如:
复制代码代码如下所示:
SQL >选择outer.employee_id,outer.last_name,outer.salary,outer.department_id
2从hr.employees外
3在outer.salary >
4(选择AVG(内部工资))
5从hr.employees内
6在inner.department_id =外department_id);
执行计划
----------------------------------------------------------
计划哈希值:2167610409
----------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
----------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 17 765 8(25)| 00:00:01 |
|×1 |哈希连接| | | | 17 765 8(25)| 00:00:01 |
| 2 |观| vw_sq_1 | | | 11 286 4(25)| 00:00:01 |
3哈希组| | | | | | 11 77 4(25)| 00:00:01 |
4表访问全|员工| | | | | 107 749 3(0)| 00:00:01 |
5表访问全| | |员工| | | 107 2033 3(0)| 00:00:01 |
----------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1访问(item_1=外。department_id )
过滤器(外部)。工资>AVG(内部工资)
上面的查询是将查询到一个哈希视图与主查询,以及查询转换后实际上是这样的:
复制代码代码如下所示:
SQL >选择outer.employee_id,outer.last_name,outer.salary,outer.department_id
2从hr.employees外,
3(选择department_id,AVG(工资)的department_id hr.employees组从avg_sal)内
4在inner.department_id = outer.department_id和outer.salary > inner.avg_sal;
事实上,这两份声明的执行计划也是一致的。
三,谓词向前推
将谓词从内部查询块推入非联合查询块,使谓词条件更早被选择,提前过滤不必要的数据行,提高效率。它还允许一些索引以这种方式使用。
复制代码代码如下所示:
谓词向前推的一个例子
SQL > AutoTrace traceonly解释
SQL >选择e1.last_name,e1.salary,v.avg_salary
2从hr.employees E1,
3(选择department_id,AVG(工资)avg_salary
4从hr.employees E2
5组department_id)V
6在e1.department_id = v.department_id
7、e1.salary > v.avg_salary
8、e1.department_id = 60;
执行计划
----------------------------------------------------------
计划哈希值:3521487559
-----------------------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 1 41 3(0)| 00:00:01 |
| 1 |嵌套循环| | | | | |
| 2 |嵌套循环| | | | 1 41 3(0)| 00:00:01 |
| 3 |观| | | | 1 26 2(0)| 00:00:01 |
4哈希组| | | | | | 1 7 2(0)| 00:00:01 |
| 5表访问的索引rowid |员工| | | | 5 35 2(0)| 00:00:01 |
6索引范围扫描| * | | emp_department_ix | 5 | | 1(0)| 00:00:01 |
7索引范围扫描| * | | emp_department_ix | 5 | | 0(0)| 00:00:01 |
| * 8表访问的索引rowid | |员工| | | 1 15 1(0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
6访问(department_id= 60)
7 -访问()。department_id= 60)
8 -过滤器()。工资>V。avg_salary )
非谓语前向推进
SQL >选择e1.last_name,e1.salary,v.avg_salary
2从hr.employees E1,
3(选择department_id,AVG(工资)avg_salary
4从hr.employees E2
5在rownum > 1行号等于no_merge和no_push_pred提示同时使用,禁用视图合并和谓词推进
6组department_id)V
7在e1.department_id = v.department_id
8、e1.salary > v.avg_salary
9、e1.department_id = 60;
执行计划
----------------------------------------------------------
计划哈希值:3834222907
--------------------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
--------------------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 3 123 7(29)| 00:00:01 |
|×1 |哈希连接| | | | 3 123 7(29)| 00:00:01 |
| 2表访问的索引rowid |员工| | | | 5 75 2(0)| 00:00:01 |
3索引范围扫描| * | | emp_department_ix | 5 | | 1(0)| 00:00:01 |
|×4 |观| | | | 11 286 4(25)| 00:00:01 |
5哈希组| | | | | | 11 77 4(25)| 00:00:01 |
| 6 |计数| | | | | |
|×7 |滤波器| | | | | |
8表访问全| | |员工| | | 107 749 3(0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1 -访问()。department_id=V。department_id )
筛选器(。工资>V。avg_salary )
3 -访问()。department_id= 60)
4过滤器(。department_id= 60)
7过滤器(rownum > 1)
两个以上查询可以在第一个查询看到,的department_id = 60谓词推入在V的观点,这使得内部视图查询只需要获得了60的平均工资系数;而平均工资计算每个部门第二查询,然后使用department_id = 60与过滤器查询连接的外部条件,相对来说在这里等待查询谓词中的应用,并做更多的工作。
四。使用物化视图进行查询重写
作为一个物化视图中打开查询重写,CBO优化器将评估相应的查询的基表和视图的访问成本,如果优化器从视图的查询结果可以得到更有效的,那么它将对物化视图进行自动选择,或对基表的查询计划生成。
或板栗:
复制代码代码如下所示:
SQL > AutoTrace traceonly解释
SQL >选择department_id,计数(employee_id)从员工的department_id组;
执行计划
----------------------------------------------------------
计划哈希值:1192169904
--------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
--------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 11 33 4(25)| 00:00:01 |
1哈希组| | | | | | 11 33 4(25)| 00:00:01 |
2表访问全|员工| | | | | 107 321 3(0)| 00:00:01 |
--------------------------------------------------------------------------------
-创建物化视图日志
在序列中创建实化视图日志,
2(employee_id rowid,department_id)包括新的价值观;
创建实体化视图日志。
-创建物化视图并指定查询重写功能
SQL >创建物化视图mv_t
2在提交时立即刷新
3启用查询重写
4选择department_id,计数(employee_id)从员工的department_id组;
创建实体化视图。
SQL >选择department_id,计数(employee_id)从员工的department_id组;
执行计划
----------------------------------------------------------
计划哈希值:1712400360
-------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
-------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 12 312 3(0)| 00:00:01 |
| 1 mat_view重写访问全| mv_t | | | | 12 312 3(0)| 00:00:01 |
-------------------------------------------------------------------------------------
注
—
用于此语句的动态采样(级别= 2)
可以在第二个查询中看到,虽然查询指定了员工表,但是优化器自动选择了物化视图的执行路径,因为它判断物化视图已经记录了当前查询结果需要设置的数据,直接访问物化视图的效率更高。
值得注意的是,物化视图的查询重写这是自动的,也可以使用 / * +重写(mv_t)*提示方式强制查询重写。
总结:
虽然查询优化器重写我们的用户结构在透明的情况下,但通常都是基于CBO优化模式的判断更加有效率的选择,这是我们所期望的,但也为我们提供了一个学习方法,是时候考虑在编写SQL语句的过程优化的作用。
我们知道查询块是通过选择关键字来区分的。查询写的方式决定了查询块之间的关系。每个查询块通常嵌入在另一个查询块中或以某种方式连接。
复制代码代码如下所示:
选择*从员工那里department_id在(选择department_id部门)
它们是嵌套的查询块,但是它们的目的是探究如果查询改变了,是否提供了更好的查询计划。
查询转换步骤是完全透明的用户,可以说知道转换器可能不会改变对你的SQL语句的结构完全重写的情况下查询的结果,所以我们重新评估查询他们的心理预期是必要的,但这种转换总体上是好的,为了得到更有效的执行计划。
现在我们讨论几个基本的转换:
1。视图合并
2。子查询解决嵌套
三.谓词推进
4。物化视图查询重写
一、视图合并
这种方式很容易理解。它将把嵌入式视图扩展为独立的查询块,或者将查询的其余部分与一般的执行计划相结合。转换后的语句基本不包含视图。
视图合并通常发生在外部查询块的谓词包括:
1,可以在另一个查询块的索引中使用的列
2,可以在另一个查询块的分区截断中使用的列
3,可以限制连接视图中返回行数的条件
在这样的查询转换中,视图并不总是有自己的子查询计划,这是预先分析的,通常与查询的其他部分合并以获得性能改进。
复制代码代码如下所示:
SQL > AutoTrace traceonly解释
视图合并
从雇员A,
2(选择department_id员工)b_view
3在a.department_id = b_view.department_id(+)
4、a.salary > 3000;
执行计划
----------------------------------------------------------
计划哈希值:1634680537
----------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
----------------------------------------------------------------------------------------
| 0 | SELECT语句| | | 3161 222k | 3(0)| 00:00:01 |
1嵌套循环外| | | | | 3161 222k | 3(0)| 00:00:01 |
2表访问全|员工| * | | | | 103 7107 3(0)| 00:00:01 |
3索引范围扫描| * | | emp_department_ix | | | 31 93 0(0)| 00:00:01 |
----------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
2过滤器()。工资> > 3000
3 -访问(。department_id=department_id (+))
使用no_merge防止重写的意见
从雇员A,
2(选择 / * * / + no_merge department_id员工b_view)
3在a.department_id = b_view.department_id(+)
4、a.salary > 3000;
执行计划
----------------------------------------------------------
计划哈希值:1526679670
-----------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
-----------------------------------------------------------------------------------
| 0 | SELECT语句| | | 3161 253k | 7(15)| 00:00:01 |
1哈希连接右外| | * | | | 3161 253k | 7(15)| 00:00:01 |
| 2 |观| | | | 107 1391 3(0)| 00:00:01 |
3表访问全| | |员工| | | 107 321 3(0)| 00:00:01 |
4表访问全| * | |员工| | | 103 7107 3(0)| 00:00:01 |
-----------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1 -访问(。department_id=b_view 。department_id (+))
4过滤器()。工资> > 3000
在某些情况下,视图合并将被禁止或限制,如果一个查询块中使用的功能,分析聚合函数,并设置操作(如工会、相交、减),在通过的条款,任何一个,这是命令和行号;尽管如此,我们仍然可以使用 / * +合并(V)* /提示强制视图组合使用,但前提必须是确保返回的结果集是一致的!!!以下示例如下:
复制代码代码如下所示:
SQL >集AutoTrace
-使用聚合函数AVG导致视图合并失败
SQL >选择e1.last_name,e1.salary,v.avg_salary
2从hr.employees E1,
3(选择department_id,AVG(工资)avg_salary
4从hr.employees E2
5组department_id)V
6在e1.department_id = v.department_id和e1.salary > v.avg_salary;
执行计划
----------------------------------------------------------
计划哈希值:2695105989
----------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
----------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 17 697 8(25)| 00:00:01 |
|×1 |哈希连接| | | | 17 697 8(25)| 00:00:01 |
| 2 |观| | | | 11 286 4(25)| 00:00:01 |
3哈希组| | | | | | 11 77 4(25)| 00:00:01 |
4表访问全|员工| | | | | 107 749 3(0)| 00:00:01 |
5表访问全| | |员工| | | 107 1605 3(0)| 00:00:01 |
----------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1 -访问()。department_id=V。department_id )
筛选器(。工资>V。avg_salary )
合并使用(合并)
SQL >选择合并(V) / / * + e1.last_name,e1.salary,v.avg_salary
2从hr.employees E1,
3(选择department_id,AVG(工资)avg_salary
4从hr.employees E2
5组department_id)V
6在e1.department_id = v.department_id和e1.salary > v.avg_salary;
执行计划
----------------------------------------------------------
计划哈希值:3553954154
----------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
----------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 165 5610 8(25)| 00:00:01 |
|×1 |滤波器| | | | | |
2哈希组| | | | | | 165 5610 8(25)| 00:00:01 |
|×3 |哈希连接| | | 3296 109k | 7(15)| 00:00:01 |
4表访问全|员工| | | | | 107 2889 3(0)| 00:00:01 |
5表访问全|员工| | | | | 107 749 3(0)| 00:00:01 |
----------------------------------------------------------------------------------
二、子查询解决嵌套
最典型的方法是对表连接进行子查询。它与视图合并的主要区别在于它的子查询位于WHERE子句中,嵌套检测由转换器完成。
下面是一个子查询表连接示例:
复制代码代码如下所示:
SQL >选择employee_id,last_name,工资,department_id
2从hr.employees
3 department_id在哪里
4(选择department_id)
5从hr.departments哪里location_id > 1700);
执行计划
----------------------------------------------------------
计划哈希值:432925905
---------------------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
---------------------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 34 884 4(0)| 00:00:01 |
| 1 |嵌套循环| | | | | |
| 2 |嵌套循环| | | | 34 884 4(0)| 00:00:01 |
| 3表访问的索引rowid |部门| | | | 4 28 2(0)| 00:00:01 |
4索引范围扫描| * | | dept_location_ix | 4 | | 1(0)| 00:00:01 |
5索引范围扫描| * | | emp_department_ix | 10 | | 0(0)| 00:00:01 |
| 6表访问的索引rowid | |员工| | | 10 190 1(0)| 00:00:01 |
---------------------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
4访问(location_id> 1700)
5访问(department_id=department_id )
使用 / * * / + no_unnest被迫分开的子查询执行计划生成
SQL >选择employee_id,last_name,工资,department_id
2从hr.employees
3 department_id在哪里
4(选择no_unnest * / / * + department_id
5从hr.departments哪里location_id > 1700);
执行计划
----------------------------------------------------------
计划哈希值:4233807898
--------------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
--------------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 10 190 14(0)| 00:00:01 |
|×1 |滤波器| | | | | |
2表访问全| | |员工| | | 107 2033 3(0)| 00:00:01 |
| * 3表访问的索引rowid |部门| | | | 1 7 1(0)| 00:00:01 |
4索引唯一扫描| * | | dept_id_pk | 1 | | 0(0)| 00:00:01 |
--------------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1过滤器(存在(选择 / * + no_unnest×0从人力资源部门。
部门,department_id=:B1和location_id> 1700))
3过滤器(location_id> 1700)
4访问(department_id=:B1)
你可以看到任何嵌套查询子查询的解决方案只使用滤波器两表,第一步的查询谓词的信息并没有变化,这意味着107排的雇员表中返回的每一行必须执行子查询。尽管在Oracle的子查询缓存优化我们不能判断两者的计划的缺点,但相比于嵌套循环,过滤操作的缺点是很明显的。
如果有相关的子查询,嵌套过程通常将相关子查询转换成非嵌套视图,然后与主查询中的表x连接,例如:
复制代码代码如下所示:
SQL >选择outer.employee_id,outer.last_name,outer.salary,outer.department_id
2从hr.employees外
3在outer.salary >
4(选择AVG(内部工资))
5从hr.employees内
6在inner.department_id =外department_id);
执行计划
----------------------------------------------------------
计划哈希值:2167610409
----------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
----------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 17 765 8(25)| 00:00:01 |
|×1 |哈希连接| | | | 17 765 8(25)| 00:00:01 |
| 2 |观| vw_sq_1 | | | 11 286 4(25)| 00:00:01 |
3哈希组| | | | | | 11 77 4(25)| 00:00:01 |
4表访问全|员工| | | | | 107 749 3(0)| 00:00:01 |
5表访问全| | |员工| | | 107 2033 3(0)| 00:00:01 |
----------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1访问(item_1=外。department_id )
过滤器(外部)。工资>AVG(内部工资)
上面的查询是将查询到一个哈希视图与主查询,以及查询转换后实际上是这样的:
复制代码代码如下所示:
SQL >选择outer.employee_id,outer.last_name,outer.salary,outer.department_id
2从hr.employees外,
3(选择department_id,AVG(工资)的department_id hr.employees组从avg_sal)内
4在inner.department_id = outer.department_id和outer.salary > inner.avg_sal;
事实上,这两份声明的执行计划也是一致的。
三,谓词向前推
将谓词从内部查询块推入非联合查询块,使谓词条件更早被选择,提前过滤不必要的数据行,提高效率。它还允许一些索引以这种方式使用。
复制代码代码如下所示:
谓词向前推的一个例子
SQL > AutoTrace traceonly解释
SQL >选择e1.last_name,e1.salary,v.avg_salary
2从hr.employees E1,
3(选择department_id,AVG(工资)avg_salary
4从hr.employees E2
5组department_id)V
6在e1.department_id = v.department_id
7、e1.salary > v.avg_salary
8、e1.department_id = 60;
执行计划
----------------------------------------------------------
计划哈希值:3521487559
-----------------------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
-----------------------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 1 41 3(0)| 00:00:01 |
| 1 |嵌套循环| | | | | |
| 2 |嵌套循环| | | | 1 41 3(0)| 00:00:01 |
| 3 |观| | | | 1 26 2(0)| 00:00:01 |
4哈希组| | | | | | 1 7 2(0)| 00:00:01 |
| 5表访问的索引rowid |员工| | | | 5 35 2(0)| 00:00:01 |
6索引范围扫描| * | | emp_department_ix | 5 | | 1(0)| 00:00:01 |
7索引范围扫描| * | | emp_department_ix | 5 | | 0(0)| 00:00:01 |
| * 8表访问的索引rowid | |员工| | | 1 15 1(0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
6访问(department_id= 60)
7 -访问()。department_id= 60)
8 -过滤器()。工资>V。avg_salary )
非谓语前向推进
SQL >选择e1.last_name,e1.salary,v.avg_salary
2从hr.employees E1,
3(选择department_id,AVG(工资)avg_salary
4从hr.employees E2
5在rownum > 1行号等于no_merge和no_push_pred提示同时使用,禁用视图合并和谓词推进
6组department_id)V
7在e1.department_id = v.department_id
8、e1.salary > v.avg_salary
9、e1.department_id = 60;
执行计划
----------------------------------------------------------
计划哈希值:3834222907
--------------------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
--------------------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 3 123 7(29)| 00:00:01 |
|×1 |哈希连接| | | | 3 123 7(29)| 00:00:01 |
| 2表访问的索引rowid |员工| | | | 5 75 2(0)| 00:00:01 |
3索引范围扫描| * | | emp_department_ix | 5 | | 1(0)| 00:00:01 |
|×4 |观| | | | 11 286 4(25)| 00:00:01 |
5哈希组| | | | | | 11 77 4(25)| 00:00:01 |
| 6 |计数| | | | | |
|×7 |滤波器| | | | | |
8表访问全| | |员工| | | 107 749 3(0)| 00:00:01 |
--------------------------------------------------------------------------------------------------
谓词信息(由操作ID标识):
离开
1 -访问()。department_id=V。department_id )
筛选器(。工资>V。avg_salary )
3 -访问()。department_id= 60)
4过滤器(。department_id= 60)
7过滤器(rownum > 1)
两个以上查询可以在第一个查询看到,的department_id = 60谓词推入在V的观点,这使得内部视图查询只需要获得了60的平均工资系数;而平均工资计算每个部门第二查询,然后使用department_id = 60与过滤器查询连接的外部条件,相对来说在这里等待查询谓词中的应用,并做更多的工作。
四。使用物化视图进行查询重写
作为一个物化视图中打开查询重写,CBO优化器将评估相应的查询的基表和视图的访问成本,如果优化器从视图的查询结果可以得到更有效的,那么它将对物化视图进行自动选择,或对基表的查询计划生成。
或板栗:
复制代码代码如下所示:
SQL > AutoTrace traceonly解释
SQL >选择department_id,计数(employee_id)从员工的department_id组;
执行计划
----------------------------------------------------------
计划哈希值:1192169904
--------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
--------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 11 33 4(25)| 00:00:01 |
1哈希组| | | | | | 11 33 4(25)| 00:00:01 |
2表访问全|员工| | | | | 107 321 3(0)| 00:00:01 |
--------------------------------------------------------------------------------
-创建物化视图日志
在序列中创建实化视图日志,
2(employee_id rowid,department_id)包括新的价值观;
创建实体化视图日志。
-创建物化视图并指定查询重写功能
SQL >创建物化视图mv_t
2在提交时立即刷新
3启用查询重写
4选择department_id,计数(employee_id)从员工的department_id组;
创建实体化视图。
SQL >选择department_id,计数(employee_id)从员工的department_id组;
执行计划
----------------------------------------------------------
计划哈希值:1712400360
-------------------------------------------------------------------------------------
我的名字|操作| | |行| |字节成本(CPU)时间| |
-------------------------------------------------------------------------------------
| 0 | SELECT语句| | | | 12 312 3(0)| 00:00:01 |
| 1 mat_view重写访问全| mv_t | | | | 12 312 3(0)| 00:00:01 |
-------------------------------------------------------------------------------------
注
—
用于此语句的动态采样(级别= 2)
可以在第二个查询中看到,虽然查询指定了员工表,但是优化器自动选择了物化视图的执行路径,因为它判断物化视图已经记录了当前查询结果需要设置的数据,直接访问物化视图的效率更高。
值得注意的是,物化视图的查询重写这是自动的,也可以使用 / * +重写(mv_t)*提示方式强制查询重写。
总结:
虽然查询优化器重写我们的用户结构在透明的情况下,但通常都是基于CBO优化模式的判断更加有效率的选择,这是我们所期望的,但也为我们提供了一个学习方法,是时候考虑在编写SQL语句的过程优化的作用。
声明:本文内容用于数码产品信息整理与选购参考,具体价格、库存、售后政策以官方渠道和电商页面实时信息为准。