首页 > 大数据 > 正文

Replace操作CLOB致临时表空间泄露

2010-11-05 17:19:22  来源:博客

摘要:生产系统抛ORA-01652错误,找到跑错的程序,发现是下面一段代码(这里只是演示代码,不是原代码)抛出的
关键词: Oracle Ora
 生产系统抛ORA-01652错误,找到跑错的程序,发现是下面一段代码(这里只是演示代码,不是原代码)抛出的:
package_body ppp
  aaa clob;

...
procedure change_content()

begin
。。。

  aaa :
= replace(aaa, 'b', ';;');
。。。

end;




procedure call_f()
begin
  aaa :
= empty_clob();

  aaa :
= 'aaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaabaaaaaaaaaaaaa';

  
for i in 1..10000 loop
change_content();

  
end loop;

end;

  从逻辑上看,这段代码可以用以下代码进行模拟,

declare

  aaa clob;

begin

  aaa :
= empty_clob();

  aaa :
= 'aaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaabaaaaaaaaaaaaa';

  
for i in 1..10000 loop

    aaa :
= replace(aaa, 'b', ';;');

  
end loop;

end;

  我们知道,在PLSQL中的LOB类型变量是占用临时表空间的。但是,从以上代码看,CLOB变量aaa的初始值并没有占用太大空间。我们在测试环境上运行该语句,用以下语句观察其临时表空间占用情况。

SELECT b.tablespace,

       
ROUND(((b.blocks*p.value)/1024/1024),2)||'M' "SIZE",

       b.CONTENTS,

       s.sql_text,

       a.sid||
','||a.serial# SID_SERIAL,

       a.username,

       a.program,

       sysdate 
as log_date

  FROM sys.v_$session a,

       sys.v_$sort_usage b,

       sys.v_$parameter p,

       v$sqlarea s

WHERE p.name  
= 'db_block_size'

   
AND a.saddr = b.session_addr

   
AND a.sql_address = s.address and a.sql_hash_value = s.hash_value

ORDER BY b.tablespace, b.blocks;

TABLESPACE       SIZE     CONTENTS SQL_TEXT SID_SERIAL       USERNAME PROGRAM  LOG_DATE
---------------------------------------------------------------------------------
TEMP     37M      TEMPORARY        declare   aaa clob; begin   aaa :
= empty_clob();   aaa := 'aaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaaabaaaaaaaaaaaaabaaaaaaaaaaaaa';   for i in 1..1000000000 loop     aaa := replace(aaa, 'a', ';;');   end loop; end;          137,28675        DEMO     plsqldev.exe     8/15/2007 11:42:11 

  发现临时表空间在不停增长。问题就在于aaa := replace(aaa, 'b', ';;').Replace()函数会先将传入的CLOB参数变量在temp空间上保存一份,然后再转换为varchar2类型进行操作。这样,每次进行了replace操作后,就多占据了一份temp空间。

  我们可以通过包dbms_lob中提供的copy、instr和write函数来自己编写一个clob的字符替换函数,来避免temp空间的泄露。以下存储过程实现了CLOB中的字符串替换。

create or replace procedure lob_replace( p_lob in out clob,

                       p_what in varchar2,

                       p_with in varchar2 )

as

    n    number;

    
len  number;

begin

    n :
= dbms_lob.instr( p_lob, p_what );

    
while ( nvl(n,0> 0 ) loop

        
len := dbms_lob.getlength(p_lob);

        
if (n+length(p_with)-1 > len)

        
then

            dbms_lob.writeappend( p_lob, n
+length(p_with)-1 - len, p_with );

        
end if;

        

        
if (len-n-length(p_what)+1 > 0)

        
then

            dbms_lob.copy( p_lob,

                           p_lob,

                           
len-n-length(p_what)+1,

                           n
+length(p_with),

                           n
+length(p_what) );

        
end if;



        dbms_lob.write( p_lob, length(p_with), n, p_with );

        

        
if ( length(p_what) > length(p_with) )

        
then

            dbms_lob.trim( p_lob,

               dbms_lob.getlength(p_lob)
-(length(p_what)-length(p_with)) );

        
end if;

        n :
= dbms_lob.instr( p_lob, p_what );

    
end loop;

end;

  用以上过程代替replace函数,再次运行程序,用以上语句观察,不再存在临时空间泄露。


第三十五届CIO班招生
国际CIO认证培训
首席数据官(CDO)认证培训
责编:lyre

免责声明:本网站(http://www.ciotimes.com/)内容主要来自原创、合作媒体供稿和第三方投稿,凡在本网站出现的信息,均仅供参考。本网站将尽力确保所提供信息的准确性及可靠性,但不保证有关资料的准确性及可靠性,读者在使用前请进一步核实,并对任何自主决定的行为负责。本网站对有关资料所引致的错误、不确或遗漏,概不负任何法律责任。
本网站刊载的所有内容(包括但不仅限文字、图片、LOGO、音频、视频、软件、程序等)版权归原作者所有。任何单位或个人认为本网站中的内容可能涉嫌侵犯其知识产权或存在不实内容时,请及时通知本站,予以删除。