热门标签 | 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的专栏

推荐阅读
  • 探讨如何高效使用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 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • 本文详细介绍了如何通过多种编程语言(如PHP、JSP)实现网站与MySQL数据库的连接,包括创建数据库、表的基本操作,以及数据的读取和写入方法。 ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • Python自动化处理:从Word文档提取内容并生成带水印的PDF
    本文介绍如何利用Python实现从特定网站下载Word文档,去除水印并添加自定义水印,最终将文档转换为PDF格式。该方法适用于批量处理和自动化需求。 ... [详细]
  • 在当前众多持久层框架中,MyBatis(前身为iBatis)凭借其轻量级、易用性和对SQL的直接支持,成为许多开发者的首选。本文将详细探讨MyBatis的核心概念、设计理念及其优势。 ... [详细]
  • 360SRC安全应急响应:从漏洞提交到修复的全过程
    本文详细介绍了360SRC平台处理一起关键安全事件的过程,涵盖从漏洞提交、验证、排查到最终修复的各个环节。通过这一案例,展示了360在安全应急响应方面的专业能力和严谨态度。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • 扫描线三巨头 hdu1928hdu 1255  hdu 1542 [POJ 1151]
    学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ... [详细]
  • 本文详细介绍了W3C标准盒模型和IE传统盒模型的区别,探讨了CSS3中box-sizing属性的使用方法及其在布局中的重要性。通过实例分析,帮助读者更好地理解和应用这一关键概念。 ... [详细]
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社区 版权所有