热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

解析Oracle数据扫描OracleSQL优化引导局部扫描方法(7)

相关链接解析Oracle数据扫描OracleSQL优化引导局部扫描方法(1)http://www.2cto.com/database/201205/130424.html;解析Oracle数据扫描OracleSQL优化引导局部扫描方法(2)http://www.2cto.com/database/20...
相关链接
解析Oracle数据扫描Oracle SQL优化引导局部扫描方法(1)
http://www.2cto.com/database/201205/130424.html;
解析Oracle数据扫描Oracle SQL优化引导局部扫描方法(2)
http://www.2cto.com/database/201205/130428.html;
解析Oracle数据扫描Oracle SQL优化引导局部扫描方法(3)
http://www.2cto.com/database/201205/130432.html;
解析Oracle数据扫描Oracle SQL优化引导局部扫描方法(4)
http://www.2cto.com/database/201205/130439.html;
解析Oracle数据扫描Oracle SQL优化引导局部扫描方法(5)
http://www.2cto.com/database/201205/130593.html;
解析Oracle数据扫描Oracle SQL优化引导局部扫描方法(6)
http://www.2cto.com/database/201205/130758.html
 
通过编写PL/SQL函数实现局部范围扫描
 
       通过Oracle提供的PL/SQL编程语言,可以实现创建过程化SQL函数。在函数中不仅可以存在一个以上的SQL,而且还可以存在多样化的运算、条件处理、循环执行等语句。它依据外部所接受的值或固定的常量来执行必要的数据处理,并返回一个最终的处理结果。因此,我们可以通过编写函数,来处理复杂全局数据范围的运算,并通过函数将这些操作包装起来,从而避免向优化器提供选择使用全局范围扫描的机会,以确保语句按照局部范围扫描来执行。
 
       函数的处理特点是,每次函数只会返回一个处理结果,同时每次只处理对象集合中的一行数据,因此当需要获得多个结果时就必须反复执行,所以如果是大范围数据的批量处理,那么建议还是不要使用函数处理为好,可见在使用函数时一定要注意函数的上述特点,不能随意使用否则无法达到我们期望的效果。  www.2cto.com  
 
下面通过两个应用实例来说明如何通过函数实现局部范围扫描,以及使用函数实现局部范围扫描的应用场合。
 
实例1:在前面说明如何利用嵌套视图实现局部范围扫描时,我们通过标量子查询实现了对分组操作的局部范围扫描,但是我们也说明了标量子查询并不是每个版本都提供支持,其实还以通过采用函数的方式来实现局部范围扫描。具体实现方式与步骤如下所示:
 
(1)    编写一个函数实现分组统计:
 
Create or replace function Get_avg_Stock(v_start in date,
 
                                  v_end in date,
 
                                  v_product_cd in varchar2)
 
return  number is
 
ret_val  number(10);
 
begin
 
select sum(stock_qty)/(v_end-v_start) into ret_val
 
from prod_stock
 
where product_cd=v_product_cd
 
and stock_date between v_start and v_end;
 
return ret_val;  www.2cto.com  
 
end Get_avg_Stock;
 
(2)    使用函数编写SQL语句实现原有功能:
 
Select product_cd,product_name,
 
Get_avg_Stock(to_date(‘2010-01-01’,’yyyy-mm-dd’),
 
to_date(‘2010-12-31’,’yyyy-mm-dd’),
 
product_cd)
 
          from product
 
          where category_cd=’20’;
 
通过上两个步骤,实现了将原来操作中的全部范围扫描的包装,并使得整个语句实现了局部范围扫描。
 
实例二:在进行具有1:M关系的两张表的连接操作时,连接的结果会是M的集合,如果连接的目的是为了实现让M方的表针对从1方的表读出的中间结果进行校验,那么此时就会发生耗时全部范围数据扫描操作,因为为了将连接后的“M”集合简化为原来的“1”集合,需要进行额外的group by、distinct等操作,这大大增加了执行代价,因此尽量不要进行这种性质的连接操作。但当出现这种情况的需求时,可以通过实现函数来实现数据局部范围扫描,提升查询性能。见如下语句:
 
Select y.cust_no,y.cust_name,x.bill_tot
 
From (select a.cust_no,sum(b.bill_amt) bill_tot
 
     From account a,charge b
 
     Where a.acct_no=b.acct_no
 
     And a.bill_cd=’FEE’ and b.bill_ym between ‘2010’ and ‘2011’
 
     Grouo by a.cust_no  www.2cto.com  
 
     Having sum(b.bill_amt)>5000000) x,customer y
 
Where y.cust_no=x.cust_no and y.cust_type=’IC’ and rownum<=30;
 
      该语句实现查询在2010年到2011年间,贸易总额在500万以上并且已经付款完成交易的前30位大客户信息。该语句执行过程中,优化器会制定首先执行内部的分组统计子查询,获得查询结果后再将结果与customer表进行连接,最后返回前30为大客户信息。在将子查询与customer表进行关联时,在连接条件y.cust_no=x.cust_no上其实进行的是用交易信息过滤客户信息,而客户信息与交易信息是1:M的关系,因此此时带来了额外的group by、distinct等引发全局范围扫描的操作,致使执行过程中处理了大量不必要的数据,导致执行性能低下。
 
      如果优化器能够制定,首先以客户类型为大客户“IC”的数据集对象,在子查询中查询他们的交易信息,并在达到30名的限度时终止执行,此时就可以实现局部范围数据扫描,同时也可以获得非常好的执行性能。我们仍然可以通过函数来实现这个优化的执行计划,实现步骤如下:
 
(1)    定义函数:
 
Create or replace function Cust_IC_Fee(v_cust_no in varchar2,
 
                                v_start_year  in varchar2,
 
                                v_end_year  in varchar2)
 
return number is
 
ret_var number(10);
 
begin  www.2cto.com  
 
select sum(bill_amt) into ret_var
 
from account a,charge b
 
where a.acct_no=b.acct_no
 
and a.cust_no=v_cust_no and b.bill_cd=’FEE’
 
and b.bill_ym between v_start_year and v_end_year;
 
return ret_val;
 
end Cust_IC_Fee;
 
(2)    使用函数编写SQL语句实现原有功能:
 
Select cust_no,cust_name, Cust_IC_Fee(cust_no,’ 2010’, ‘2011’)
 
From customer
 
Where cust_type=’IC’
 
And Cust_IC_Fee(cust_no,’ 2010’, ‘2011’)>=5000000
 
And rownum<=30;
 
        通过使用函数来重新改写原来的语句实现,实现了优化的执行计划同时也使实现了局部范围数据扫描,执行性能得到了提升,但是当前还是存在一定的缺陷,那就是where条件中的函数虽然和select中的函数相同,但是却需要在执行时分别运行,这是由于函数的执行机制决定的,我们无法左右,在函数重复执行对系统不造成负担的情况下,可以放心使用,但是一旦函数重复执行对系统造成了一定的负担,此时我们就不能再使用这种方法了,而只能寻求其他的解决途径了。
 
一个比较简单的处理方法是运用嵌套视图来改写原来的语句,如下所示:
 
Select cust_no,cust_name,bill_tot
 
From (select rownum,cust_no,cust_name,
 
Cust_IC_Fee(cust_no,’ 2010’, ‘2011’) bill_tot
 
      From customer  www.2cto.com  
 
      Where cust_type=’IC’)
 
Where bill_tot>5000000
 
And rownum<=30;
 
       该语句的玄机在于子查询中的rownum的运用,从前面关于rownum虚拟列特性的讨论中可以知道,子查询的rownum与主查询的rownum代表的意义完全不同,因此当在子查询中使用了rownum,优化器必须要将子查询的执行结果存储在内部临时存储区域中,所以子查询中的函数被执行一次后就将其结果存在了内部临时存储区域内,而此时主查询的查询对象就是存储在内部临时存储区域中的数据集合,因此通过使用嵌套视图实现了只执行一次函数的目的,此时内部子查询和外部主查询都会按照局部范围扫描的方式来运行,因此查询性能会得到很大的提升。
 
       但是如果将内部的rownum去掉,那么执行过程就大不一样了,此时内部子查询的函数可能会被执行多次,因为没有机制来保证内部子查询的结果会被首先保存在内部临时存储区域内,因此函数会被执行的次数可能会与满足cust_type=’IC’条件的记录数目相同。虽然此时内部子查询也可能是局部范围扫描,但此时的局部范围扫描由于不能将结果存放在内部临时存储区域中,而只能直接填充批量数组,同时填充过程中可能还要与外部主查询条件bill_tot>5000000发生交互作用,所以函数可能会被多次调用执行。  www.2cto.com  
 
      可见这种方法的关键在于,设法将内部子查询的结果缓存在内部临时存储区域中,除了使用rownum外还有很多方法可以实现这个目的,如:order by、group by等操作,也同样会驱动子查询的结果被保存在内部临时存储区域中。

 
 
摘自 javacoffe的专栏

推荐阅读
  • Docker的安全基准
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 程序员妻子吐槽:丈夫北漂8年终薪3万,存款情况令人意外
    一位程序员的妻子在网上分享了她丈夫在北京工作八年的经历,月薪仅3万元,存款情况却出乎意料。本文探讨了高学历人才在大城市的职场现状及生活压力。 ... [详细]
  • 在 Windows 10 中,F1 至 F12 键默认设置为快捷功能键。本文将介绍几种有效方法来禁用这些快捷键,并恢复其标准功能键的作用。请注意,部分笔记本电脑的快捷键可能无法完全关闭。 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 探讨如何高效使用FastJSON进行JSON数据解析,特别是从复杂嵌套结构中提取特定字段值的方法。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • PHP 5.2.5 安装与配置指南
    本文详细介绍了 PHP 5.2.5 的安装和配置步骤,帮助开发者解决常见的环境配置问题,特别是上传图片时遇到的错误。通过本教程,您可以顺利搭建并优化 PHP 运行环境。 ... [详细]
  • 本文详细介绍了HTML中标签的使用方法和作用。通过具体示例,解释了如何利用标签为网页中的缩写和简称提供完整解释,并探讨了其在提高可读性和搜索引擎优化方面的优势。 ... [详细]
  • 本文深入探讨 MyBatis 中动态 SQL 的使用方法,包括 if/where、trim 自定义字符串截取规则、choose 分支选择、封装查询和修改条件的 where/set 标签、批量处理的 foreach 标签以及内置参数和 bind 的用法。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 非公版RTX 3080显卡的革新与亮点
    本文深入探讨了图形显卡的进化历程,重点介绍了非公版RTX 3080显卡的技术特点和创新设计。 ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 导航栏样式练习:项目实例解析
    本文详细介绍了如何创建一个具有动态效果的导航栏,包括HTML、CSS和JavaScript代码的实现,并附有详细的说明和效果图。 ... [详细]
author-avatar
unforgettable602
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有