現象:job一直運行,抽取一直在運行,通過過程中的日誌記錄定位到是因為抽取X系統資料一直卡著。但是查詢正在執行的sql,沒有任何結果,抽取這部分資料一直運行了一天,還未完。
因為定位不到是哪條sql在運行,於是停job,手動運行這部分的資料幫浦,已耗用時間與正常抽取的時間相近,之前查看系統cpu,io均沒有異常,懷疑是因為這部分sql的執行計畫改變所致。
調出系統中的執行計畫與手動啟動並執行sql的執行計畫進行對比,一條sql的執行計畫在月初由hash join 變為nested loops。
--1.由於定位了sql,尋找sql的sql_id
select sql_id,address,plan_hash_value,hash_value,child_number,sql_text from v$sql
where sql_text like 'INSERT INTO XXX%'
--2.dba_hist_sql_plan視圖顯示了曆史的執行計畫,TIMESTAMP欄位指該執行計畫產生的時間
select * from dba_hist_sql_plan h where sql_id='7sjn92j0k8csm';
每個不同的plan_hash_value值代表一個不同的執行計畫。這條對應兩個執行計畫,在月初的時候新產生了一個計劃(串連方式是nested loops),Oracle使用了最新的執行計畫。
--3.顯示所有詳細的執行計畫
select plan_table_output from table(dbms_xplan.display_awr('7xh0wcw1qt6d7'));
解決方案:使用use_hash hint或使用outlines穩固執行計畫, 因為時間原因,最後採用了使用hint的方式。hash join 不僅解決了nested loops串連中大量隨機讀取的問題,還解決了排序合并串連中排序代價過大的問題。hash join不同於nested loop按照隨機讀取的方式進行串連,它需要提前將連線物件集中到一起,然後在記憶體中按照雜湊讀取的方式進行串連。排序合并串連可以參考:
查看計劃的兩種方式:
DBMS_XPLAN.DISPLAY_AWR(
sql_id IN VARCHAR2,
plan_hash_value IN NUMBER DEFAULT NULL,
db_id IN NUMBER DEFAULT NULL,
format IN VARCHAR2 DEFAULT TYPICAL);
sql_id
Specifies the SQL_ID of the SQL statement. You can retrieve the appropriate value for the SQL statement of interest by querying the column SQL_ID in DBA_HIST_SQLTEXT.
DBMS_XPLAN.DISPLAY_CURSOR(
sql_id IN VARCHAR2 DEFAULT NULL,
child_number IN NUMBER DEFAULT NULL,
format IN VARCHAR2 DEFAULT 'TYPICAL');
sql_id
Specifies the SQL_ID of the SQL statement in the cursor cache. You can retrieve the appropriate value by querying the column SQL_ID in V$SQL or V$SQLAREA. Alternatively, you could choose the column PREV_SQL_ID for a specific session out of V$SESSION. This parameter defaults to NULL in which case the plan of the last cursor executed by the session will be displayed.