此脚本不依赖统计信息。

    在编写 PLSQL 的时候,我们应该尽量避免 LOOP 套 LOOP,因为双层循环,最内层循环类似笛卡儿积。假设外层循环返回 1 000 行数据,内层循环返回 1 000 行数据,那么内层循环里面的代码就会执行 1000*1000 次。以下脚本可以抓出 LOOP 套 LOOP 的 PLSQL。

    1. with x as
    2. (select /*+ materialize */ owner,name,type,line,text,rownum rn from dba_source where (upper(text) like '%END%LOOP%' or upper(text) like '%FOR%LOOP%'))
    3. select a.owner,a.name,a.type from x a,x b
    4. where ((upper(a.text) like '%END%LOOP%'
    5. and upper(b.text) like '%END%LOOP%'
    6. and a.rn+1=b.rn)
    7. or (upper(a.text) like '%FOR%LOOP%'
    8. and upper(b.text) like '%FOR%LOOP%'
    9. and a.rn+1=b.rn))
    10. and a.owner=b.owner
    11. and a.name=b.name
    12. and a.type=b.type
    13. and a.owner='SCOTT';

    我们在 Scott 账户中创建 LOOP 套 LOOP 的存储过程。

    1. create or replace procedure p_99 is
    2. begin
    3. for i in 1 .. 9 loop
    4. dbms_output.put_line('');
    5. for x in 1 .. 9 loop
    6. if (i >= x) then
    7. dbms_output.put(' ' || i || ' x ' || x || ' = ' || i * x);
    8. end if;
    9. end loop;
    10. dbms_output.put_line('');
    11. end loop;
    12. end;

    我们通过脚本将以上的存储过程抓出。

    1. with x as
    2. (select /*+ materialize */ owner,name,type,line,text,rownum rn from dba_source
    3. where (upper(text) like '%END%LOOP%' or upper(text) like '%FOR%LOOP%'))
    4. select distinct a.owner,a.name,a.type from x a,x b
    5. where ((upper(a.text) like '%END%LOOP%'
    6. and upper(b.text) like '%END%LOOP%'
    7. and a.rn+1=b.rn)
    8. or (upper(a.text) like '%FOR%LOOP%'
    9. and upper(b.text) like '%FOR%LOOP%'
    10. and a.rn+1=b.rn))
    11. and a.owner=b.owner
    12. and a.name=b.name
    13. and a.type=b.type
    14. and a.owner='SCOTT';
    1. OWNER NAME TYPE
    2. --------------- --------------- ---------------
    3. SCOTT P_99 PROCEDURE