♣题目 部分
在Oracle中,查询转换包含哪些类型?
♣答案部分
在Oracle数据库中,用户发给Oracle让其执行的目标SQL和Oracle实际执行的SQL有可能是不同的,这是因为Oracle可能会对执行的目标SQL做等价改写,即查询转换。查询转换(Query Transformation),也叫逻辑优化(Logical Optimization),又称为查询改写(Query Rewrite)或软优化,即查询转换器在逻辑上对语句做一些语义等价转换,它是Oracle在解析目标SQL的过程中的非常重要的一步。查询转换能使优化器将目标SQL改写成语义上完全等价的SQL语句但生成的执行计划效率更高。
查询转换器依据特定的方式决定是否对查询块进行转换。按照其所依赖的方式,转换技术可以分为两类:①启发式查询转换(Heuristic Query Transformation),又称为基于规则的查询转换(Rule Based Query Transformation),启发式查询转换是基于一套规则对查询进行转换,一旦满足规则所定义的条件,则对语句进行相应的转换。启发式查询转换需要从10053事件信息中查找有关查询转换的线索,并且许多跟踪记录仅能从Oracle 11g的跟踪信息中发现。②基于代价的查询转换(Cost Based Query Transformation,CBQT)。基于代价的查询转换是否对语句进行转换则取决于语义等价语句之间的代价对比,即采用代价最小的一种。大多数基于代价的查询转换可以从执行计划的概要数据中找到线索。Oracle提供了一个隐含参数“_OPTIMIZER_COST_BASED_TRANSFORMATION”用以控制是否进行基于代价的查询转换,以及如何进行基于代价的查询转换,从而限制其对资源的消耗。
Oracle中常见的查询转换分类如下图所示:
1SYS@orclasm > SET PAGESIZE 9999 2SYS@orclasm > SET LINE 9999 3SYS@orclasm > COL NAME FORMAT A40 4SYS@orclasm > COL KSPPDESC FORMAT A50 5SYS@orclasm > COL KSPPSTVL FORMAT A20 6SYS@orclasm > SELECT A.INDX, 7 2 A.KSPPINM NAME, 8 3 A.KSPPDESC, 9 4 B.KSPPSTVL 10 5 FROM X$KSPPI A,11 6 X$KSPPCV B12 7 WHERE A.INDX = B.INDX13 8 AND LOWER(A.KSPPINM) LIKE LOWER('%&PARAMETER%');14Enter value for parameter: _OPTIMIZER_COST_BASED_TRANSFORMATION15old 8: AND LOWER(A.KSPPINM) LIKE LOWER('%&PARAMETER%')16new 8: AND LOWER(A.KSPPINM) LIKE LOWER('%_OPTIMIZER_COST_BASED_TRANSFORMATION%')1718 INDX NAME KSPPDESC KSPPSTVL19---------- ---------------------------------------- -------------------------------------------------- --------------------20 1935 _optimizer_cost_based_transformation enables cost-based query transformation LINEARSET PAGESIZE 9999 2SYS@orclasm > SET LINE 9999 3SYS@orclasm > COL NAME FORMAT A40 4SYS@orclasm > COL KSPPDESC FORMAT A50 5SYS@orclasm > COL KSPPSTVL FORMAT A20 6SYS@orclasm > SELECT A.INDX, 7 2 A.KSPPINM NAME, 8 3 A.KSPPDESC, 9 4 B.KSPPSTVL 10 5 FROM X$KSPPI A, 11 6 X$KSPPCV B 12 7 WHERE A.INDX = B.INDX 13 8 AND LOWER(A.KSPPINM) LIKE LOWER('%&PARAMETER%'); 14Enter value for parameter: _OPTIMIZER_COST_BASED_TRANSFORMATION 15old 8: AND LOWER(A.KSPPINM) LIKE LOWER('%&PARAMETER%') 16new 8: AND LOWER(A.KSPPINM) LIKE LOWER('%_OPTIMIZER_COST_BASED_TRANSFORMATION%') 17 18 INDX NAME KSPPDESC KSPPSTVL 19---------- ---------------------------------------- -------------------------------------------------- -------------------- 20 1935 _optimizer_cost_based_transformation enables cost-based query transformation LINEAR
Oracle中常见的查询转换分类如下表所示:
关于上表中的内容需要注意以下几点:
① 子查询展开通常都会提高原SQL的执行效率,因为如果原SQL不做子查询展开,那么通常情况下该子查询就会在其执行计划的最后一步才被执行,并且会走FILTER类型的执行计划,这也就意味着对于外部查询所在结果集的每一条记录,该子查询就会被执行多少次,这种执行方式的执行效率通常情况不会太高,尤其在子查询中包含两个或两个以上表连接时,此时做子查询展开后的执行效率往往会比走FILTER类型的执行计划高很多。
② 使用视图合并技术后,优化器不再单独为每个视图生成子计划,而是将视图的查询合并到整体查询中去,最终为合并和整体查询寻找到一个最优的执行计划。
③ 一般来说,如果Oracle没有做视图合并的话,那么在该SQL的执行计划中就会见到“VIEW”关键字,并且该关键字所对应的NAME列的值就是该视图的名称。
④ 由于查询转换的分类非常多,本书只对常见的重要的查询转换做介绍,其余的查询转换可以阅读其它相关的书籍。
为了方便,使用黄玮老师提供的一个存储过程sql_explain:
1------------------------------------------------------------ 2-- 《SQL优化与调优技术详解》 --- 3-- 文件:02_01_SQL_Explain_11g.sql --- 4-- 作者:黄玮 --- 5-- 网站:WWW.HelloDBA.COM --- 6-- Coyprigh (c):WWW.HelloDBA.COM 保留所有权利 --- 7-- 描述:解析和显示语句执行计划 --- 8------------------------------------------------------------ 910/***********************************************************11** 用于11G **12***********************************************************/13create or replace procedure sql_explain (stmt varchar2, 14 format varchar2 default 'ADVANCED', 15 exponly boolean default true)16------------------------------------------------------------17-- 描述:解析和显示语句执行计划 ---18-- 来源:WWW.HelloDBA.COM ---19-- Coyprigh (c):WWW.HelloDBA.COM 保留所有权利 ---20-- ---21-- 参数描述 ---22-- stmt:解析或执行的语句 ---23-- format:执行计划输出格式,参加DBMS_XPLAN中描述 ---24-- exponly:是否仅解析 ---25-- TRUE:仅调用EXPLAIN PLAN命令解析语句 ---26-- FALSE:执行语句后从缓存获得执行计划 ---27------------------------------------------------------------28 AUTHID CURRENT_USER 29as30 c number;31 r number;32 sqlid varchar2(100);33 childnum number;34begin35 dbms_output.enable(50000);36 if exponly then37 execute immediate 'explain plan for '||stmt;38 for xpl_rec in ( select * from table(dbms_xplan.display(null,null,format)) ) loop39 dbms_output.put_line(xpl_rec.plan_table_output);40 end loop;41 else42 c := dbms_sql.open_cursor;43 dbms_sql.parse(c,stmt,dbms_sql.native);44 r := dbms_sql.execute_and_fetch(c);45 loop46 exit when r <= 0;47 r := dbms_sql.fetch_rows(c);48 end loop;49 select distinct p.sql_id, p.child_number into sqlid, childnum 50 from v$sql_cursor sc, v$sql_plan p, v$open_cursor c, v$sqlarea q 51 where p.address=sc.PARENT_HANDLE and p.sql_id=q.sql_id and c.sql_id = q.sql_id and c.sid = SYS_CONTEXT('USERENV','SID') and q.sql_text like substr(stmt,0,30)||chr(37) and rownum<=1;52 --select distinct s.sql_id, s.child_number into sqlid, childnum from v$sql_plan s, v$sql_cursor c where s.address=c.PARENT_HANDLE and c.curno=c and rownum<=1;53 dbms_sql.close_cursor(c);54 for xpl_rec in ( select * from table(dbms_xplan.display_cursor(sqlid,childnum,format)) ) loop55 dbms_output.put_line(xpl_rec.plan_table_output);56 end loop;57 end if;58 rollback;59end;60/6162grant execute on sql_explain to public;63create or replace public synonym sql_explain for sys.sql_explain;------------------------------------------------------------ 2-- 《SQL优化与调优技术详解》 --- 3-- 文件:02_01_SQL_Explain_11g.sql --- 4-- 作者:黄玮 --- 5-- 网站:WWW.HelloDBA.COM --- 6-- Coyprigh (c):WWW.HelloDBA.COM 保留所有权利 --- 7-- 描述:解析和显示语句执行计划 --- 8------------------------------------------------------------ 9 10/*********************************************************** 11** 用于11G ** 12***********************************************************/ 13create or replace procedure sql_explain (stmt varchar2, 14 format varchar2 default 'ADVANCED', 15 exponly boolean default true) 16------------------------------------------------------------ 17-- 描述:解析和显示语句执行计划 --- 18-- 来源:WWW.HelloDBA.COM --- 19-- Coyprigh (c):WWW.HelloDBA.COM 保留所有权利 --- 20-- --- 21-- 参数描述 --- 22-- stmt:解析或执行的语句 --- 23-- format:执行计划输出格式,参加DBMS_XPLAN中描述 --- 24-- exponly:是否仅解析 --- 25-- TRUE:仅调用EXPLAIN PLAN命令解析语句 --- 26-- FALSE:执行语句后从缓存获得执行计划 --- 27------------------------------------------------------------ 28 AUTHID CURRENT_USER 29as 30 c number; 31 r number; 32 sqlid varchar2(100); 33 childnum number; 34begin 35 dbms_output.enable(50000); 36 if exponly then 37 execute immediate 'explain plan for '||stmt; 38 for xpl_rec in ( select * from table(dbms_xplan.display(null,null,format)) ) loop 39 dbms_output.put_line(xpl_rec.plan_table_output); 40 end loop; 41 else 42 c := dbms_sql.open_cursor; 43 dbms_sql.parse(c,stmt,dbms_sql.native); 44 r := dbms_sql.execute_and_fetch(c); 45 loop 46 exit when r <= 0; 47 r := dbms_sql.fetch_rows(c); 48 end loop; 49 select distinct p.sql_id, p.child_number into sqlid, childnum 50 from v$sql_cursor sc, v$sql_plan p, v$open_cursor c, v$sqlarea q 51 where p.address=sc.PARENT_HANDLE and p.sql_id=q.sql_id and c.sql_id = q.sql_id and c.sid = SYS_CONTEXT('USERENV','SID') and q.sql_text like substr(stmt,0,30)||chr(37) and rownum<=1; 52 --select distinct s.sql_id, s.child_number into sqlid, childnum from v$sql_plan s, v$sql_cursor c where s.address=c.PARENT_HANDLE and c.curno=c and rownum<=1; 53 dbms_sql.close_cursor(c); 54 for xpl_rec in ( select * from table(dbms_xplan.display_cursor(sqlid,childnum,format)) ) loop 55 dbms_output.put_line(xpl_rec.plan_table_output); 56 end loop; 57 end if; 58 rollback; 59end; 60/ 61 62grant execute on sql_explain to public; 63create or replace public synonym sql_explain for sys.sql_explain;