广告
返回顶部
首页 > 资讯 > 数据库 >Oracle 查询转换之子查询展开
  • 273
分享到

Oracle 查询转换之子查询展开

2024-04-02 19:04:59 273人浏览 安东尼
摘要

概念:子查询展开(Subquery Unnesting)是优化器处理带子查询的目标sql的一种优化手段,它是指优化器不再将目标sql中子查询当作一个独立的处理单元来单独执行,而是将该子查询转换为它自身和外部

概念:子查询展开(Subquery Unnesting)是优化器处理带子查询的目标sql的一种优化手段,它是指优化器不再将目标sql中子查询当作一个独立的处理单元来单独执行,而是将该子查询转换为它自身和外部查询之间等价的表连接。这种等价连接转换要么是将子查询展开(即将该子查询中的表,视图从子查询中拿出来,然后和外部查询中的表,视图做表连接),要么是不拆开但是会把该子查询转换为一个内嵌视图(Inline View)然后再和外部查询中的表,视图做表连接。oracle 会确保子查询展开所对应的等价连接转换的正确性,即转换后的sql和原sql在语义上一定是等价的。当然不是所有的子查询都能做子查询展开,有些子查询是不能做这种等价表连接转换的,这种情况下oracle就不会对其做子查询展开,也就是说此时oracle还是会将该子查询当作一个独立的处理单元来单独执行。另外,在oracle10g以后版本中,对于那种不拆开子查询但是会把该子查询转换成一个内嵌视图的子查询展开,只有当经过子查询展开后的等价改写sql的成本值小于原sql的成本值时,oracle才会对原sql执行子查询展开

    子查询展开通常都会提高原sql的执行效率,因为如果原sql不做子查询展开,那么通常情况下该子查询就会在其执行计划的最后一步才被执行,并且会走filter类型的执行计划,这也就意味着对于外部查询所在结果集的没一条记录,该子查询就会被执行多少次,这种执行方式的执行效率通常情况不会太高,尤其在子查询中包含两个或两个以上表连接时,此时做子查询展开后的执行效率往往会比走filter类型的执行计划高很多。

    Oracle 数据库里子查询前where条件如果是如下这些条件之一,那么这种类型的目标sql在满足了一定条件后就可以做子查询展开,

single-row,exists,not exists,in ,not in,any,all。

范例1:

SQL> set lines 200 pagesize 1000
in写法:
SELECT t1.cust_last_name, t1.cust_id
  FROM customers t1
 WHERE t1.cust_id IN
  4         (SELECT t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700)
  5  ;
Execution Plan
----------------------------------------------------------
Plan hash value: 2448612695
----------------------------------------------------------------------------------------------------------
| Id  | Operation     | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     | |  7059 |   158K| |  1583   (1)| 00:00:20 | | |
|*  1 |  HASH JOIN SEMI      | |  7059 |   158K|  1360K|  1583   (1)| 00:00:20 | | |
|   2 |   TABLE ACCESS FULL  | CUSTOMERS | 55500 |   704K| |   405   (1)| 00:00:05 | | |
|   3 |   PARTITION RANGE ALL| |   560K|  5469K| |   526   (2)| 00:00:07 |     1 |    28 |
|*  4 |    TABLE ACCESS FULL | SALES |   560K|  5469K| |   526   (2)| 00:00:07 |     1 |    28 |
----------------------------------------------------------------------------------------------------------
Predicate InfORMation (identified by operation id):
---------------------------------------------------
any等价写法:
SELECT t1.cust_last_name, t1.cust_id
  FROM customers t1
 WHERE t1.cust_id = ANY
  4   (SELECT t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700)
  5  ;
Execution Plan
----------------------------------------------------------
Plan hash value: 2448612695
----------------------------------------------------------------------------------------------------------
| Id  | Operation     | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     | |  7059 |   158K| |  1583   (1)| 00:00:20 | | |
|*  1 |  HASH JOIN SEMI      | |  7059 |   158K|  1360K|  1583   (1)| 00:00:20 | | |
|   2 |   TABLE ACCESS FULL  | CUSTOMERS | 55500 |   704K| |   405   (1)| 00:00:05 | | |
|   3 |   PARTITION RANGE ALL| |   560K|  5469K| |   526   (2)| 00:00:07 |     1 |    28 |
|*  4 |    TABLE ACCESS FULL | SALES |   560K|  5469K| |   526   (2)| 00:00:07 |     1 |    28 |
----------------------------------------------------------------------------------------------------------
exists等价写法:
SELECT t1.cust_last_name, t1.cust_id
  FROM customers t1
 WHERE t1.cust_id = ANY
  4   (SELECT t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700)
  5  ;
Execution Plan
----------------------------------------------------------
Plan hash value: 2448612695
----------------------------------------------------------------------------------------------------------
| Id  | Operation     | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     | |  7059 |   158K| |  1583   (1)| 00:00:20 | | |
|*  1 |  HASH JOIN SEMI      | |  7059 |   158K|  1360K|  1583   (1)| 00:00:20 | | |
|   2 |   TABLE ACCESS FULL  | CUSTOMERS | 55500 |   704K| |   405   (1)| 00:00:05 | | |
|   3 |   PARTITION RANGE ALL| |   560K|  5469K| |   526   (2)| 00:00:07 |     1 |    28 |
|*  4 |    TABLE ACCESS FULL | SALES |   560K|  5469K| |   526   (2)| 00:00:07 |     1 |    28 |
----------------------------------------------------------------------------------------------------------
不展开,显然不合理,sales表要执行很多次:
SELECT t1.cust_last_name, t1.cust_id
  FROM customers t1
 WHERE t1.cust_id IN (SELECT 
                       t2.cust_id
                        FROM sales t2
                       WHERE t2.amount_sold > 700)

子查询展开后,变成hash 半连接:

等价写法:(如果cust_id是唯一键值)可以转换为内连接:

SELECT t1.cust_last_name, t1.cust_id
  FROM customers t1, sales t2
 WHERE t1.cust_id= t2.cust_id
   AND t2.amount_sold > 700

如果是not in,则会转换为hash 反连接:

SQL> set autot trace
SELECT t1.cust_last_name, t1.cust_id
  FROM customers t1
 WHERE t1.cust_id not in 
  4   (SELECT t2.cust_id FROM sales t2 WHERE t2.amount_sold > 700);
Execution Plan
----------------------------------------------------------
Plan hash value: 2850422635
----------------------------------------------------------------------------------------------------------
| Id  | Operation     | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     | | 48441 |  1088K| |  1583   (1)| 00:00:20 | | |
|*  1 |  HASH JOIN ANTI      | | 48441 |  1088K|  1360K|  1583   (1)| 00:00:20 | | |
|   2 |   TABLE ACCESS FULL  | CUSTOMERS | 55500 |   704K| |   405   (1)| 00:00:05 | | |
|   3 |   PARTITION RANGE ALL| |   560K|  5469K| |   526   (2)| 00:00:07 |     1 |    28 |
|*  4 |    TABLE ACCESS FULL | SALES |   560K|  5469K| |   526   (2)| 00:00:07 |     1 |    28 |
----------------------------------------------------------------------------------------------------------

把子查询转换成内联视图:

SELECT t1.cust_last_name, t1.cust_id
  FROM customers t1
 WHERE t1.cust_id NOT IN
       (SELECT t2.cust_id
          FROM sales t2, products t3
         WHERE t2.prod_id = t3.prod_id and t2.amount_sold > 700)
Execution Plan
----------------------------------------------------------
Plan hash value: 1272298339
--------------------------------------------------------------------------------------------------------------
| Id  | Operation       | Name     | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
--------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |     | 48441 |1229K|     |1665   (1)| 00:00:20 |     |     |
|*  1 |  HASH JOIN ANTI        |     | 48441 |1229K|1360K|1665   (1)| 00:00:20 |     |     |
|   2 |   TABLE ACCESS FULL    | CUSTOMERS   | 55500 | 704K|     | 405   (1)| 00:00:05 |     |     |
|   3 |   VIEW       | VW_NSO_1    | 560K|7110K|     | 529   (2)| 00:00:07 |     |     |
|*  4 |    HASH JOIN       |     | 560K|9844K|     | 529   (2)| 00:00:07 |     |     |
|   5 |     INDEX FULL SCAN    | PRODUCTS_PK |  72 | 288 |     |   1   (0)| 00:00:01 |     |     |
|   6 |     PARTITION RANGE ALL|     | 560K|7657K|     | 526   (2)| 00:00:07 |   1 |  28 |
|*  7 |      TABLE ACCESS FULL | SALES     | 560K|7657K|     | 526   (2)| 00:00:07 |   1 |  28 |
--------------------------------------------------------------------------------------------------------------

这里oracle把子查询转换成内联视图 VM_NSO_1,然后再和外部查询中的表customers做hash半连接。

等价:

SELECT t1.cust_last_name, t1.cust_id
  FROM customers t1,
       (SELECT t2.cust_id
          FROM sales t2, products t3
         WHERE t2.prod_id = t3.prod_id
           AND t2.amount_sold > 700) vm_nso_1
 WHERE t1.cust_id semi = vm_nso_1.cust_id

子查询是否能够做子查询展开取决于如下两个条件:

    子查询展开所对应的等价改写sql和原sql在语义上一定要完全等价的,如果改写后的sql和原sql并不一定能保持语义上的完全等价,这种类型的子查询就不能做子查询展开。

    对于不能拆开的子查询但是会把它转换为一个内嵌视图的子查询展开,只有经过子查询展开的等价改写sql成本值小于原sql的成本值。oracle才会对目标sql执行子查询展开。

对于子查询展开的第一种情形(即将子查询展开,把该子查询中的表,视图从子查询中拿出来,然后和外部查询中表,视图做表连接),即使在oracle  10g以后的版本中,oracle也不会考虑子查询展开的成本,即oracle此时会认为这种情形下子查询展开的效率始终比不展开的效率高,这就意味着如果目标sql满足子查询展开的第一种情形。则oracle始终会做子查询展开,而不管经过子查询展开后的等价sql的成本值是否小于原sql的成本值。


您可能感兴趣的文档:

--结束END--

本文标题: Oracle 查询转换之子查询展开

本文链接: https://www.lsjlt.com/news/50645.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Oracle 查询转换之子查询展开
    概念:子查询展开(Subquery Unnesting)是优化器处理带子查询的目标sql的一种优化手段,它是指优化器不再将目标sql中子查询当作一个独立的处理单元来单独执行,而是将该子查询转换为它自身和外部...
    99+
    2022-10-18
  • Oracle 12CR2查询转换之临时表转换
    在12CR2中出现一种新的查询转换技术临时表转换, 在下面的例子中,数据库对customers表上的子查询结果物化到一个临时表中: SQL> show parameter&n...
    99+
    2022-10-18
  • Oracle 笔记之子查询
    子查询当我们的一个操作需要基于另一个查询记过,那么就先行执行的这个查询就是子查询子查询分为:单行单列子查询:查的结果只有一行,且只有一个字段多行单列子查询:查询出来的结果有多行,但只有一列 多行多列子查询查...
    99+
    2022-10-18
  • Oracle 查询转换初探
    概述Oracle查询转换器的作用是把原始sql重写为语义相同的语句,目的是为了获得更高效的sql。查询转换主要有四种技术:子查询展开,视图合并,谓词推入,星型转换。了解查询转换是掌握SQL优化的基础,本文将...
    99+
    2022-10-18
  • Oracle-子查询
    一、WHERE条件中的子查询1. 比black工资高的雇员有哪些select ename from empwhere sal>(select sal f...
    99+
    2022-10-18
  • oracle子查询
    最近在加强oracle查询,在网上看到了一个不错的视频,把学习笔记和大家分享一下oracle 子查询的语法(即select语句的嵌套)子查询要注意的问题:  1.子查询语法中的小括号&n...
    99+
    2022-10-18
  • Oracle 12CR2查询转换之星型转换的方法
    这篇文章主要为大家展示了“Oracle 12CR2查询转换之星型转换的方法”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Oracle 12CR2查询转换之星型转...
    99+
    2022-10-18
  • Oracle 12CR2查询转换之视图合并
    这里的测试数据库版本为12.2.0.1,在视图合并中,优化器代表视图的查询块到包含视国的查询块中。视图合并通过让优化器考虑额外的连接顺序,访问方法与其它转换来提高性能。例如,在一个视图被合并后并且在一个查...
    99+
    2022-10-18
  • MySQL之连接查询和子查询
    多表连接的基本语法 多表连接,就是将几张表拼接为一张表,然后进行查询 select 字段1, 字段2, ... from 表1 {inner|lift|right} join 表2 on 连接条件; 有如下两张表:部门表和员工...
    99+
    2015-01-24
    MySQL之连接查询和子查询
  • Oracle查询转换之连接谓词推入
    连接谓词推入(Join Predicate  Pushdown)是优化器处理带视图的目标SQL的一种优化手段,它是指虽然优化器会把该SQL中视图的定义SQL语句当作一个独立单元来单独执行,但此时优...
    99+
    2022-10-18
  • Oracle专题8之Oracle的子查询
    1、Oracle的子查询的概述 什么是子查询? 子查询是指嵌入在其他SQL语句中的SELECT语句,也称之为嵌套查询。 可以使用子查询的位置:where、select列表、havin&#...
    99+
    2022-10-18
  • Oracle 12CR2查询转换教程之临时表转换详解
    前言 大家都知道在12CR2中出现一种新的查询转换技术临时表转换, 在下面的例子中,数据库对customers表上的子查询结果物化到一个临时表中: SQL> show parameter star...
    99+
    2022-10-18
  • Oracle12CR2查询转换之表扩展的示例分析
    这篇文章给大家分享的是有关Oracle12CR2查询转换之表扩展的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。表扩展工作原理表分区使用表扩展成为可能。如果在一个分区表上...
    99+
    2022-10-18
  • 怎么在oracle中查询操作子查询
    怎么在oracle中查询操作子查询?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、子查询语法SELECT select_l...
    99+
    2022-10-18
  • oracle标量子查询
    SQL> conn scott/scott Connected. SQL> create table a (id int,n...
    99+
    2022-10-18
  • oracle之sql查询
    oracle表管理表名和列的命名规则:必须以字母开头长度不能超过30字符不能使用oracle的保留字只能使用如下字符:A-Z,a-z,0-9,$,#等字符型:char:定长 最大2000字符例子:cha&#...
    99+
    2022-10-18
  • ORACLE中的查询转换有哪些
    本篇内容主要讲解“ORACLE中的查询转换有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“ORACLE中的查询转换有哪些”吧!一、子查询展开(subquery unnesting)子查询展开...
    99+
    2023-05-31
  • Oracle系列:(14)子查询
    子查询的作用:查询条件未知的事物查询条件已知的问题:例如:查询工资为800的员工信息查询条件未知的问题:例如:查询工资为20号部门平均工资的员工信息一个条件未知的问题,可以分解为多个条件已知的问题查询工资比...
    99+
    2022-10-18
  • MySQL数据查询之子查询的示例分析
    这篇文章主要介绍了MySQL数据查询之子查询的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。子查询是指一个查询语句嵌套在另一个查询语...
    99+
    2022-10-18
  • oracle之sql查询二
    此文章为http://huangsir007.blog.51cto.com/6159353/1854818该片的后续 关于数据库语言查询:SQL> show parameter nls_languag...
    99+
    2022-10-18
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作