4、峰回路转
为什么会有那么多次的逻辑读和递归?看来看执行计划还是太表面了,难以回答ORACLE内部在做啥小动作,不查出问题所在,不将谜团大白于天下,誓不罢休!
试试10046trace吧,看看整个执行开始到结束,到底在执行什么,等待什么?玩啥猫腻!
分别做了两次10046TRACE,具体见附件《10046trace_notebook.txt》和《10046trace_service.txt》
仔细观察,终于有重大发现了,笔记本中环境10046trace_notebook.txt
SELECT PERSON
FROM
TACHE WHERE FLOW_ID = :B1 AND STATE <> 'F'
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 65249 2.26 1.90 0 0 0 0
Fetch 65249 1.23 1.30 0 65243 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 130499 3.50 3.20 0 65243 0 0
这里怎么跑出一个这样的语句,Eeecute6万多次最终获取0行
而10046trace_service.txt中类似的地方确实如下,rows显示为65331和前者为0!有所发现。
SELECT PERSON
FROM
TACHE WHERE FLOW_ID = :B1 AND STATE <> 'F'
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 65339 0.78 0.75 0 0 0 0
Fetch 130670 148.79 145.17 0 32714110 0 65331
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 196010 149.58 145.93 0 32714110 0 65331
继续分析发现 10046trace_service.txt还有如下调用,而10046trace_notebook.txt根本找不到如下两处调用!
SELECT PKP_FLOW_FUNCTION.GETSTAFFNAMEBYID(LTRIM(RTRIM(TO_CHAR(:B1 ))))
FROM
DUAL
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 522102 7.43 6.78 0 0 0 0
Fetch 522102 42.59 42.17 0 0 0 522102
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 1044205 50.03 48.96 0 0 0 522102
SELECT NAME
FROM
STAFF_INFO WHERE STAFF_ID = :B1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 522102 8.51 7.78 0 0 0 0
Fetch 522102 21.35 20.21 0 4110939 0 456771
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 1044205 29.86 27.99 0 4110939 0 456771
仔细观察,还有新发现, 10046trace_service.txt还有如下递归调用 统计信息,而10046trace_notebook.txt
根本找不到!
RECURSIVE STATEMENTS
OVERALL TOTALS FOR ALL RECURSIVE STATEMENTS
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 11 0.00 0.01 0 0 0 0
Execute 1109552 16.74 15.33 0 0 0 0
Fetch 1174883 212.73 207.57 1 36825069 0 1044211
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2284446 229.48 222.92 1 36825069 0 1044211
看来,这个递归毫无疑问来自函数的调用,仔细回到复杂的SQL脚本一看,发现了原先SQL中有函数
Pkp_Flow_Function.Getflowcurstaffname(a.Flow_Id) Flow_Operator,
查看这个函数调用的代码写法
FUNCTION getFlowCurStaffName(in_flow_id in number) RETURN VARCHAR2 IS
ss VARCHAR2(255);
person1 VARCHAR2(255);
v_tabArray PKP_STRING_UTIL.varArray;
CURSOR c2 IS
SELECT person
FROM tache
WHERE flow_id = in_flow_id
AND STATE <> 'F';
BEGIN
--从环节表中取得
FOR rel1 IN c2 LOOP
v_tabArray := PKP_STRING_UTIL.split(rel1.person, ',');
FOR i IN 1 .. v_tabArray.COUNT() LOOP
SELECT getStaffNameById(LTRIM(RTRIM(TO_CHAR(v_tabArray(i)))))
INTO person1
FROM dual;
ss := ss || person1 || ' ';
END LOOP;
END LOOP;
RETURN(ss);
END getFlowCurStaffName;
其中getFlowCurStaffName函数还调用了getStaffNameById函数,具体如下:
FUNCTION getStaffNameById(in_staff_id IN varchar2) return varchar2 is
ret varchar2(255);
begin
select NAME INTO ret FROM STAFF_INFO WHERE STAFF_ID = in_staff_id;
return(ret);
end getStaffNameById;
而这些语句都出现在刚才的 10046trace_service.txt中,看来问题就出在这个函数调用中了!
虽然函数中的语句为什么与部分没有出现在10046trace_notebook.txt中这个问题我还无法回答,但是我相信,真相已经离我们很近了!
[本帖最后由 wabjtam123 于 2010-3-16 13:01 编辑]
2010-3-16 13:01 上传
点击文件名下载附件
16.89 KB, 下载次数: 48
2010-3-16 13:01 上传
点击文件名下载附件
15.57 KB, 下载次数: 49