How to Release the Temp LOB Space and Avoid Hitting ORA-1652 (文档 ID 802897.1)

时间:2021-06-06 10:52:27

APPLIES TO:

Oracle Database - Enterprise Edition - Version 8.1.5.0 and later
Information in this document applies to any platform.

GOAL

How to release Temp LOB Segment that has been created explicitly or implicitly by Oracle for intermediate stages of database processing.

SOLUTION

Prior to 10.2.0.4 
=============

Actually we have different kinds of Temporary Segments. Oracle often requires temporary work space for intermediate stages of database processing. There are different kinds of temporary segments in the database. Some of them are created explicitly by the users. The others are created and accessed for the user by the system.

Use the view V$TEMPORARY_LOBS in conjunction with DBA_SEGMENTS or V$SORT_SEGMENT to determine how much space is being used by temporary lobs. We can create an explicit temporary BLOB or CLOB and its corresponding index in the user's default tablespace calling DBMS_LOB.CREATETEMPORARY procedure, and free them by calling DBMS_LOB.FREETEMPORARY.

When calling DBMS_LOB.CREATETEMPORARY, TWO temporary extents are allocated to store LOB_DATA and one temporary extent to store LOB_INDEX in 8i. So, a total of three temporary extents are allocated in 8i. However, in 9i (Release 2) and up, only one temporary extent is allocated .

DBMS_LOB.CREATETEMPORARY can be used with limited success prior to 10.2.0.4.

The only true solution prior to 10.2.0.4 and the setting of the event (as discussed below) is to terminate the session that created the temporary lob.

10.2.0.4 and above 
===============

Two approaches are available:

1- You can use DBMS_LOB.FREETEMPORARY where the LOB locator that was freed is marked as invalid.

DBMS_LOB.FREETEMPORARY frees space from temp tablespace and it is available to that same session, but the temp segment is not released and made available to other sessions. So if the session creates another temp lob after freetemporary, the space is reused by that session.
The space is not released until the session exits. That can easily lead to an ORA-1652 error when multiple concurrent sessions are doing a huge LOB operations and not exiting, thus the freed space by DBMS_LOB.FREETEMPORARY is only available within the calling session but not for the other sessions.

-- ========
-- Session1
-- ========
-- SQL*Plus: Release 10.2.0.4.0 - Production on Tue Apr 7 09:06:31 2009

-- Copyright (c) 1982, 2007, Oracle.  All Rights Reserved.

-- Connected to:
-- Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
-- With the Partitioning, OLAP, Data Mining and Real Application Testing options

declare
  clb clob;
  ch varchar2(32767);
  k number;
begin
  dbms_lob.createtemporary(clb,true,dbms_lob.call);
    for i in 1..1500 loop
      ch:=lpad('o',32767,'Y');
      dbms_lob.writeappend(clb,length(ch),ch);
    end loop;
    k:=dbms_lob.getlength(clb);
    dbms_lob.freetemporary(clb);
    dbms_output.put_line('the clob length: '||k);
end;
/

-- PL/SQL procedure successfully completed.

select u.tablespace, u.contents, u.segtype, u.extents, u.blocks, round(((u.blocks*P.VALUE)/1024/1024),2) MB
from v$session s, v$sort_usage u, SYS.V_$SYSTEM_PARAMETER P
where s.saddr = u.session_addr 
AND UPPER(P.NAME)='DB_BLOCK_SIZE'
order by MB DESC;

TABLESPACE                      CONTENTS  SEGTYPE      EXTENTS     BLOCKS         MB
------------------------------- --------- --------- ---------- ---------- ----------
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_INDEX          1        128          1
TEMP                            TEMPORARY LOB_INDEX          1        128          1
declare
  clb clob;
  ch varchar2(32767);
  k number;
begin
  dbms_lob.createtemporary(clb,true,dbms_lob.call);
  for i in 1..1500 loop
    ch:=lpad('o',32767,'Y');
    dbms_lob.writeappend(clb,length(ch),ch);
  end loop;
  k:=dbms_lob.getlength(clb);
  dbms_lob.freetemporary(clb);
  dbms_output.put_line('the clob length: '||k);
end;
/

-- PL/SQL procedure successfully completed.

select u.tablespace, u.contents, u.segtype, u.extents, u.blocks, round(((u.blocks*P.VALUE)/1024/1024),2) MB
from v$session s, v$sort_usage u, SYS.V_$SYSTEM_PARAMETER P
where s.saddr = u.session_addr
and    UPPER(P.NAME)='DB_BLOCK_SIZE'
order by MB DESC;

TABLESPACE                      CONTENTS  SEGTYPE      EXTENTS     BLOCKS         MB
------------------------------- --------- --------- ---------- ---------- ----------
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_INDEX          1        128          1
TEMP                            TEMPORARY LOB_INDEX          1        128          1

<<<<<<<<<<<<< Only 4 rows selected >>>>>>>>>>>>>>>>

-- =========
-- session2
-- =========

declare
  clb clob;
  ch varchar2(32767);
  k number;
begin
  dbms_lob.createtemporary(clb,true,dbms_lob.call);
  for i in 1..1500 loop
    ch:=lpad('o',32767,'Y');
    dbms_lob.writeappend(clb,length(ch),ch);
  end loop;
  k:=dbms_lob.getlength(clb);
  dbms_lob.freetemporary(clb);
  dbms_output.put_line('the clob length: '||k);
end;
/

-- PL/SQL procedure successfully completed.

select u.tablespace, u.contents, u.segtype, u.extents, u.blocks, round(((u.blocks*P.VALUE)/1024/1024),2) MB
from v$session s, v$sort_usage u, SYS.V_$SYSTEM_PARAMETER P
where s.saddr = u.session_addr
and    UPPER(P.NAME)='DB_BLOCK_SIZE'
order by MB DESC;

TABLESPACE                      CONTENTS  SEGTYPE      EXTENTS     BLOCKS         MB
------------------------------- --------- --------- ---------- ---------- ----------
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_INDEX          1        128          1
TEMP                            TEMPORARY LOB_INDEX          1        128          1
TEMP                            TEMPORARY LOB_INDEX          1        128          1

6 rows selected.

-- When we disconnect session 2 now and run the same query from session 1 again we will get 4 rows only

select u.tablespace, u.contents, u.segtype, u.extents, u.blocks, round(((u.blocks*P.VALUE)/1024/1024),2) MB
from v$session s, v$sort_usage u, SYS.V_$SYSTEM_PARAMETER P
where s.saddr = u.session_addr
and UPPER(P.NAME)='DB_BLOCK_SIZE'
order by MB DESC;

TABLESPACE                      CONTENTS  SEGTYPE      EXTENTS     BLOCKS         MB
------------------------------- --------- --------- ---------- ---------- ----------
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_DATA          48       6144         48
TEMP                            TEMPORARY LOB_INDEX          1        128          1
TEMP                            TEMPORARY LOB_INDEX          1        128          1

2-Exiting the session where are the TEMP segments will be freed completely.

10.2.0.4 and above
===============

In addition to the above approaches For 10.2.0.4 and above a new event introduced (event 60025) where when set if there are no active temp lobs in the session (ie: both cache temp lob and no-cache temp lobs used are zero) then the temp segment itself will also be freed releasing the space for other sessions to use. Note that this change is disabled by default. You can set this using alter system in the system level also.

alter session set events '60025 trace name context forever';