搬運工:temp表空間被過多佔用處理方法
這個步驟比較簡單,查詢v$sort_usage就可以了:
SQL_ID都是一樣的,那這個SQL是否有其特殊性呢?SEGTYPE為SORT表明這個臨時段是“排序段”,用於SQL排序,大小居然也是一樣,會話佔用的臨時段大小將近1GB,幾百個會話加在一起,想不讓臨時表空間不撐大都難。
看看這個相同的SQL ID代表的SQL是什麼:
很明顯,這是一條非常簡單的SQL,沒有ORDER BY ,也沒有GROUP BY、UNION、DISTINCT等需要排序的,TABLE_XXX是一張普通的表,而不是檢視。出現了什麼問題?會不會是v$sort_usage的 SQL_ID列有錯誤?我們檢視其中一個會話正在執行的SQL:
v$sort_usage中看到某個會話當前沒有執行任何SQL,v$sort_usage中的SQL_ID是該會話前一條執行的SQL。為什麼這裡顯示的是會話前一條執行的SQL,關於這個問題後面再詳述,但至少有一點是可以判斷的:如果大量的臨時段都是由會話當前正在執行的SQL所產生的,那說明同時有幾百個會話在執行需要大量臨時空間的SQL,那系統早就崩潰了。所以這些臨時表空間的佔用不應該是由當前在執行的SQL所產生的,至少大部分不是。
大部分人的一個錯誤觀點是,臨時表空間中當前佔用的空間是由會話當前正在執行的SQL所產生的。上面的一個簡單的分析判斷,情況不應該是這樣。我們可以基於查詢類SQL的執行過程來分析:
- 解析SQL語句(Parse),生成一個遊標(Open Cursor)。
- 執行SQL語句(Execute),嚴格說就是執行新產生的遊標。
- 在遊標中取資料(Fetch)。
- 關閉遊標(Close Cursor)。
關鍵在第3步。大家都知道取資料有一個array size的概念,表示一次從遊標中取多少條資料,這是一個迴圈的過程。如果SQL查詢得到的資料有1000條,每次取100條,則需要取10次。對於Fetch Cursor,有兩點:
- 一個遊標,或者說一條SQL語句,並不要求客戶端把所有資料取完,只取了一部分資料就關閉遊標也是可以的。
- 只要還沒有關閉遊標,資料庫就要維護該遊標的狀態,如果是排序的SQL,也需要維持該SQL已經排好序的資料。
很顯然,從上述第2點可以知道,如果一條SQL使用了臨時段來排序,在SQL對應的遊標沒關閉的情況下,Oracle資料庫不會去釋放臨時段,因為對於Oracle資料庫來說,它不會知道客戶端是否還要繼續取遊標的資料。
基於這樣的分析,我們只需要隨便選擇一個佔用了接近1GB的會話,查詢v$open_cursor,檢視其開啟的遊標中是否有大資料量排序的SQL:
最後三個遊標,實際上都是同一條SQL語句,排序的資料量最大,我們來看看這條SQL是什麼:
基於為客戶保密的原因,SQL做了處理,能知道這條SQL的確是排了序就行,不過在SQL中看不出來的是,這條SQL沒有任何實質性的能夠過濾大量資料的條件。那麼我們count(*)這條SQL語句看看:
出來的結果居然有1200多萬條資料,一個前臺應用,不知道取1200多萬條資料幹嘛。但是從rows_processed/executions 只有幾萬的結果來看,應用在取了幾萬條資料之後,由於某些原因(最大的可能就是不能再處理更多的資料),不再繼續取資料,但是遊標也一直沒有關閉。
比較容易就能進行演示sort by時臨時表空間的佔用。
問題分析到這裡,很明顯確認的是,應用存在問題,也許是業務邏輯問題;也許是根據前臺選擇的條件拼接的SQL,但是沒有任何條件時就查詢了所有數 據。接下來就是找來開發人員,至於後面的事就跟這個主題沒有太大關係。我們可以根據這個案例來進一步展開,去探尋臨時表空間的更多知識點。
這裡要展開的第1點是,v$sort_usage中的sql_id是不是會話正在執行的SQL,我們去看看檢視fixed_View_definition就知道了:
原來在v$sort_usage的定義中,就明確地說明了SQL_ID列是v$session中的prev_sql_id列,而不是當前的SQL。至於為什麼這樣定義,老實說,現在還不知道。
不過從11.2.0.2這個版本開始,v$sort_usage的基表x$ktsso中增加了一個欄位ktssosqlid,表示該臨時段真正關聯的SQL,以上述的測試結果為例,查詢這個基表的結果如下:
可以看到的是我們查詢到了真正產生臨時段的SQL。
一直以來,v$sort_usage中的SQL_ID誤導了很多人。所幸的是Oracle從11.2.0.2開始進行了彌補,MOS中有文件:
Bug 17834663 - Include SQL ID for statement that created a temporary segment in GV$SORT_USAGE (文件 ID 17834663.8)
In previous versions, it was not possible to identify the SQL ID
of the statement that created a given temporary segment in
eg. (G)V$SORT_USAGE.
@ Via the fix for bug:8806817 we added the SQL ID to the X$KTSSO
@ table (ktssosqlid), but it was not exposed in the GV$SORT_USAGE
@ view until now.
The SQL ID of the statement is in column SQL_ID_TEMPSEG
Note that this fix cannot be provided as an interim patch.
我們改良一下v$sort_usage,使用如下的查詢來代替:
要展開的第2點是,v$sort_usage中的SEGTYPE列的不同的值各有什麼意義:
- SORT:SQL排序使用的臨時段,包括order by、group by、union、distinct、視窗函式(window function)、建索引等產生的排序。
- DATA:臨時表(Global Temporary Table)儲存資料使有的段。
- INDEX:臨時表上建的索引使用的段。
- HASH:hash演算法,如hash連線所使用的臨時段。
- LOB_DATA和LOB_INDEX:臨時LOB使用的臨時段。
根據上述的段型別,大體可以分為三類佔用:
- SQL語句排序、HASH JOIN佔用
- 臨時表佔用
- 臨時LOB物件佔用
臨時表空間的異常佔用,一種緩步增長的,另一種情況:一下撐滿的通常是一個極大資料量的排序或極大的索引的建立。緩步增長的情況,跟系統的記憶體被逐 漸佔用類似,存在“洩露”。比如排序的SQL遊標沒有關閉,比如本文的案例;比如會話級臨時表產生了資料後一直沒有清除;臨時LOB物件沒有清理或洩露。 前兩種比較好去分析處理,但是臨時LOB的洩露問題就複雜很多。
來看一個測試:
上述的程式碼執行完之後,在另一個視窗中,我們查詢v$sort_usage:
可以看到,這個會話已經產生了型別為LOB_DA他的臨時段。雖然SQL程式碼已經執行完成,會話已經處於空閒狀態,但是臨時段仍然存在著。
Oracle中的LOB變數,類似於C語句中的指標,或者類似於JAVA程式碼中的資料庫連線Connection,是需要釋放的。上述有問題的代 碼,缺少了釋放LOB的程式碼:dbms_log.freetemporary(v_lob)。好在對於這種情況,Oracle提供了一個補救措施,就是設 置60025事件可以自動清理掉不活動的LOB,只需要在引數檔案中加上event='60025 trace name context forever'。
在Oracle資料庫中,xmltype型別內部也實際上是LOB型別,xmltype型別的資料操作可能會產生較多的LOB臨時段。lob型別的 欄位上的更改操作,比如lob拼接等,同樣會產生LOB臨時段。如果在v$sort_usage中發現大量的LOB型別的臨時段,那麼通常是由於程式碼存在 問題,沒有釋放LOB,或者是由於Oracle本身的BUG。在MOS上,如果以lob temporary關鍵字搜尋,會發現相當多的關於lob臨時段的洩露或臨時段沒有釋放相關的文件。
最後,不管是什麼情況導致的臨時表空間被過多佔用,通常重啟應用能夠釋放掉臨時段,因為會話退出後,相對應的臨時段就會被釋放。看來,“重啟”大法在這種情況下就很有用。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29135257/viewspace-1793593/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle的temp表空間被佔滿Oracle
- Oracle Temp臨時表空間處理Oracle
- SYSAUX表空間佔用過大情況下的處理(AWR資訊過多)UX
- undo表空間佔用磁碟空間滿案例處理
- 處理TEMP表空間滿的問題
- TEMP表空間報ORA-1652的處理
- oracle temp 表空間Oracle
- TEMP表空間不足解決 - temp group
- sysaux 表空間爆滿處理方法UX
- 檢視單個SQL消耗TEMP表空間以及TEMP表空間使用率SQL
- undo 表空間滿了的處理方法
- 一次臨時表空間大量佔用問題的處理
- Oracle Temp 表空間切換Oracle
- Oracle Temp 臨時表空間Oracle
- undo表空間損壞的處理過程
- oracle中undo表空間丟失處理方法Oracle
- Oracle undo表空間爆滿的處理方法Oracle
- undo表空間故障處理
- Oracle TEMP臨時表空間概念Oracle
- Oracle審計--AUD$佔用空間較大處理方案Oracle
- Oracle的home目錄空間佔用異常處理Oracle
- oracle系統表空間過大問題處理Oracle
- oracle臨時表空間過大的原因&&處理Oracle
- 處理物料搬運單APIAPI
- AWR佔用sysaux表空間太大UX
- exp,imp 不同表空間大欄位處理方法
- 【TEMP】臨時表空間的工作原理及維護方法
- UNDO表空間下的資料檔案被誤刪除後的處理方法
- 臨時表空間被佔滿的原因查詢
- 回滾段表空間損壞處理(ORA-01552)處理方法
- Oracle基礎 02 臨時表空間 tempOracle
- sysaux 表空間不足問題處理UX
- UNDO表空間損壞的處理
- oracle 表空間 不足時如何處理Oracle
- Oracle一次縮小表空間的處理過程Oracle
- 如何使Xcode佔用更少的空間 Xcode佔用空間太大解決方法XCode
- 聊聊Data Guard環境下Temp表空間和Temp檔案管理
- 有關temp表空間的一點總結!