1. 程式人生 > >ORACLE 臨時表空間管理

ORACLE 臨時表空間管理

 臨時表空間和臨時段

  臨時表空間用於存放排序、臨時表等資料,其資訊不需要REDO,因此臨時表的DML操作往往比普通表產生的REDO少很多。臨時表資料變化不產生REDO,UNDO資料變化產生REDO。臨時段不僅僅存在於臨時表空間中,也可能存在普通表空間。比如通過CTAS建立一張表,新表的資料放在臨時段中,這些臨時段在CTAS完成的時候會被轉換為PERMENT段。ORACLE7.3版本之前,臨時段是在需要時分配,使用完畢後被刪除.ORACLE7.3 推出的新演算法的核心就是SEP(SORT EXTENT POOL),SEP 負責管理臨時段中擴充套件的結構,儲存在共享池內,任何需要使用排序空間的操作,都需要從SEP 中分配空閒的擴充套件,使用完畢後,不需要釋放該空間,只需要在SEP 中將該擴充套件設定為空閒。
  當資料庫例項啟動後,SMON 將會刪除該例項未釋放的臨時段,並且對臨時表空間進行碎片整理。在這個操作完成前,資料庫開啟的操作不能完成。因此每次資料庫重啟後,臨時段中的垃圾都會被完全清理。當資料庫開啟後,第一個進行的硬碟排序操作會在相關的臨時表空間內建立臨時段,這個臨時段也是整個例項唯一的臨時段(在新的臨時段演算法下,同一個表空間內,每個例項只有一個臨時段)。臨時段中擴充套件的資訊會被記錄在SEP 中。硬碟排序操作會在SEP 中查詢可用的擴充套件,在查詢前,需要獲得SORT EXTENT POOL 閂鎖。如果能找到可用的擴充套件,那麼SEP 中已被分配的擴充套件就會被標註為佔用狀態;如果找不到可用的擴充套件,那麼系統就會試圖從表空間中分配新的空間,而如果這個分配工作因為表空間的空閒空間不足而無法完成,那麼就會產生一個ORA-1652 錯誤。當排序操作完成的時候,會再次獲取SORT EXTENT POOL 閂鎖,並且將使用的擴充套件標註為空閒,然後釋放SORT EXTENT POOL 閂鎖。新的臨時表空間管理演算法不需要頻繁地分配和釋放臨時段,這大大提高了臨時段管理的效率。由於這是一種只分配不釋放的演算法,因此DBA 經常會看到自己的臨時表空間總是處於或者接近100%使用的狀態。其實對於7.3 以後的版本而言,臨時表空間使用率接近100%是十分正常的,DBA 可以通過V$SORT_USAGE 和V$SORT_SEGMENTS 這兩個檢視來檢查臨時段的使用情況。
  在RAC/OPS環境下,臨時段的管理演算法也是類似的。在RAC 中,由於多個例項會共享一個臨時表空間,因此這些例項也能夠共享相同的擴充套件。在RAC環境下,每個例項都擁有獨立的SEP,各個例項中的排序操作需要在自己的SEP中分配空間。如果SEP 中無法分配到足夠的空間,那麼首先會在表空間中分配;而如果表空間也已經分配完畢,這時若其他的例項還有空閒的擴充套件,那麼這個擴充套件就可以分配給需要的例項使用。這些操作都是不可見的,雖然SERVER 程序不會收到ORA-1652 的錯誤資訊,但是在ALTER LOG 中會有一個ORA-1652 的記錄。

臨時表空間的使用情況:
SELECT TU.TABLESPACE_NAME AS "TABLESPACE_NAME",
TT.TOTAL - TU.USED AS "FREE(G)",
TT.TOTAL AS "TOTAL(G)",
ROUND(NVL(TU.USED, 0) / TT.TOTAL * 100, 3) AS "USED(%)",
ROUND(NVL(TT.TOTAL - TU.USED, 0) * 100 / TT.TOTAL, 3) AS "FREE(%)"
FROM (SELECT TABLESPACE_NAME,
SUM(BYTES_USED) / 1024 / 1024 / 1024 USED
FROM GV_$TEMP_SPACE_HEADER
GROUP BY TABLESPACE_NAME) TU ,
(SELECT TABLESPACE_NAME,
SUM(BYTES) / 1024 / 1024 / 1024 AS TOTAL
FROM DBA_TEMP_FILES
GROUP BY TABLESPACE_NAME) TT
WHERE TU.TABLESPACE_NAME = TT.TABLESPACE_NAME;


查詢會話使用臨時表空間
SELECT SE.USERNAME,
SE.SID,
  SE.SERIAL#,
  SE.SQL_ADDRESS,
  SE.MACHINE,
  SE.PROGRAM,
  SU.TABLESPACE,
 SU.SEGTYPE,
  SU.CONTENTS  FROM V$SESSION SE,
  V$SORT_USAGE SU   WHERE SE.SADDR = SU.SESSION_ADDR;
或者:

SELECT B.TABLESPACE,
    B.SEGFILE#,
    B.SEGBLK#,
    B.BLOCKS,
    B.BLOCKS * 32 / 1024 / 1024,
    A.SID,
    A.SERIAL#,
    A.USERNAME,
    A.OSUSER,
    A.STATUS,
    C.SQL_TEXT,
    B.CONTENTS
 FROM V$SESSION A, V$SORT_USAGE B, V$SQL C
WHERE A.SADDR = B.SESSION_ADDR
  AND A.SQL_ADDRESS = C.ADDRESS(+)
  and status = 'ACTIVE'
ORDER BY B.BLOCKS DESC

檢視臨時表空間的空閒情況
SELECT TABLESPACE_NAME,FILE_ID,BYTES_USED/1024/1024,BYTES_FREE/1024/1024 FROM V$TEMP_SPACE_HEADER;


資料庫中消耗資源比較大的SQL
select se.username,
    se.sid,
    su.extents,
    su.blocks * to_number(rtrim(p.value)) as Space,
    tablespace,
    segtype,
    sql_text
from v$sort_usage su, v$parameter p, v$session se, v$sql s
where p.name = 'db_block_size'
  and su.session_addr = se.saddr
  and s.hash_value = su.sqlhash
  and s.address = su.sqladdr
order by se.username, se.sid;


或者:
select su.username,su.Extents,tablespace,segtype,sql_text  from v$sort_usage su,v$sql s Where su.SQL_ID = s.SQL_ID;


常見佔用臨時表空間的幾種情況
1:order by or group by (disc sort佔主要部分);
2:索引的建立和重建立;
3:distinct操作;
4:union & intersect & minus sort-merge joins;
5:analyze 操作;
6:有些異常也會引起TEMP的暴漲。


臨時表空間使用率過高,日常維護
確定資料庫schema的預設表空間
select username,temporary_tablespace from dba_users where account_status ='OPEN';

確定資料庫的預設臨時表空間

select * from database_properties where property_name ='DEFAULT_TEMP_TABLESPACE';

1.建立中轉臨時表空間
create temporary tablespace temp2 tempfile '/data/app/oracle/oradata/prod/temp02.dbf' size 512M reuse autoextend on next 1M maxsize unlimited;

2.改變預設臨時表空間為中轉臨時表空間TEMP2
alter database default temporary tablespace TEMP2;
驗證使用者的臨時表空間為TEMP2
select username,temporary_tablespace from dba_users where account_status ='OPEN';

3.刪除原臨時表空間
drop tablespace temp including contens and datafiles;

4.重建臨時表空間
create temporary tablespace temp tempfile '/data/app/oracle/oradata/prod/temp01.dbf' size 512M reuse autoextend on next 1M maxsize unlimited;

5.重置預設臨時表空間為新建的TEMP表空間
alter database default temporary tablespace TEMP1;

驗證使用者的臨時表空間為TEMP
select username,temporary_tablespace from dba_users where account_status ='OPEN';