免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2397 | 回复: 1
打印 上一主题 下一主题

Oracle的软解析(soft prase)和硬解析(hard prase) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-11-03 15:19 |只看该作者 |倒序浏览
说到软解析(soft prase)和硬解析(hard prase),就不能不说一下Oracle对sql的处理过程。当你发出一条sql语句交付Oracle,在执行和获取结果前,Oracle对此sql将进行几个步骤的处理过程:

1、语法检查(syntax check)
检查此sql的拼写是否语法。
2、语义检查(semantic check)
诸如检查sql语句中的访问对象是否存在及该用户是否具备相应的权限。
3、对sql语句进行解析(prase)
利用内部算法对sql进行解析,生成解析树(parse tree)及执行计划(execution plan)。
4、执行sql,返回结果(execute and return)

其中,软、硬解析就发生在第三个过程里。

Oracle利用内部的hash算法来取得该sql的hash值,然后在library cache里查找是否存在该hash值;
假设存在,则将此sql与cache中的进行比较;
假设"相同",就将利用已有的解析树与执行计划,而省略了优化器的相关工作。这也就是软解析的过程。

诚然,如果上面的2个假设中任有一个不成立,那么优化器都将进行创建解析树、生成执行计划的动作。这个过程就叫硬解析。

创建解析树、生成执行计划对于sql的执行来说是开销昂贵的动作,所以,应当极力避免硬解析,尽量使用软解析。

这就是在很多项目中,倡导开发设计人员对功能相同的代码要努力保持代码的一致性,以及要在程序中多使用绑定变量的原因。

有如下两句查询语句:

1.SELECT * FROM EMP WHERE EMPNO = 123;
2.SELECT * FROM EMP WHERE EMPNO = :EMP_NO;
1句中查询员工编号是123的员工信息,ORACLE第一次经过分析编译后执行。但如果下次还要再查询编号为456和789的员工信息时,ORACLE将会再将这句SQL分析编译,然后再执行。

再看2句,首先定义变量EMP_NO,我们将123赋给变量,第一次的时候也是经过分析编译后再执行,但是到了接下来再想查询其他员工编号的信息时,ORACLE会将第一次编译后的查询方案(在第一次编译执行之后已经储存在共享池中)用来进行下一次的查询。

这就像JAVA,想想看,如果你用JAVA写了一个软件,给客户的是你写的JAVA代码,客户在每次使用的时候都耀编译代码,然后执行。这将会影响多大啊。

所以说,分析一个带有硬编码变量的语句(称为硬分析)要明显的比重用一个已经分析过的查询方案(软分析)要花费更长的时间和耗费更多的资源。

如果使用绑定变量,提交引用相同变量的完全相同的查询的人将会使用共享池中的编译方案,只需编译子例程一次,就可以重复使用。这样不仅可以使用较少的时间,而且可以减少锁存时间,降低锁存频率。这将会提高软件性能,大大提高可伸缩性。

下面的试验将更能说明这个道理:

  1. ALTER SYSTEM FLUSH SHARED_POOL;
  2. SET SERVEROUTPUT ON;
  3. SET TIMING ON;
  4. DECLARE
  5.           TYPE rc IS REF CURSOR;
  6.           l_rc rc;
  7.           l_dummy all_objects.object_name%TYPE;
  8.           l_start NUMBER DEFAULT dbms_utility.get_time;
  9. BEGIN
  10.           FOR i IN 1 .. 1000 LOOP
  11.           OPEN l_rc FOR 'select object_name from all_objects where object_id = '||i;      
  12.           FETCH l_rc INTO l_dummy;
  13.           CLOSE l_rc;
  14.           END LOOP;
  15.           dbms_output.put_line(round((dbms_utility.get_time-l_start)/100,2)|| 'seconds ...');
  16.      END;
复制代码
PL/SQL 过程已成功完成。

已用时间:   00: 00: 53.05

上述代码使用动态SQL从ALL_OBJECTS表中查询单行。它用值1,2,3.......1000等硬编码产生1000条不同的查询进入WHERE子句,看看运行时间53秒。
再看下面代码:
  1. DECLARE
  2.         TYPE rc IS REF CURSOR;
  3.         l_rc rc;
  4.         l_dummy all_objects.object_name%TYPE;
  5.         l_start NUMBER DEFAULT dbms_utility.get_time;
  6. BEGIN
  7.         FOR i IN 1 .. 1000 LOOP
  8.         OPEN l_rc FOR 'select object_name from all_objects where object_id = :x' USING i;
  9.         FETCH l_rc INTO l_dummy;
  10.         CLOSE l_rc;
  11.         END LOOP;
  12.         dbms_output.put_line(round((dbms_utility.get_time-l_start)/100,2)|| 'seconds ...');
  13. END;
复制代码
PL/SQL 过程已成功完成。
已用时间:   00: 00: 00.03

!!!!!!!    0.03秒,差距竟然这么大,回头看代码,第二次只是在循环体中使用了变量X,将i的值赋给了X,这样一来,ORACLE在执行的时候只需要编译一次,其他999次都是从共享池中使用查询方案,查询时间和速度当然更快了。
所以。从软件开发的一开始就要认识到绑定变量的重要性。

论坛徽章:
59
2015七夕节徽章
日期:2015-08-24 11:17:25ChinaUnix专家徽章
日期:2015-07-20 09:19:30每周论坛发贴之星
日期:2015-07-20 09:19:42ChinaUnix元老
日期:2015-07-20 11:04:38荣誉版主
日期:2015-07-20 11:05:19巳蛇
日期:2015-07-20 11:05:26CU十二周年纪念徽章
日期:2015-07-20 11:05:27IT运维版块每日发帖之星
日期:2015-07-20 11:05:34操作系统版块每日发帖之星
日期:2015-07-20 11:05:36程序设计版块每日发帖之星
日期:2015-07-20 11:05:40数据库技术版块每日发帖之星
日期:2015-07-20 11:05:432015年辞旧岁徽章
日期:2015-07-20 11:05:44
2 [报告]
发表于 2010-11-03 17:19 |只看该作者
理解内部工作机制能够更好的学习ORACLE。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP