OceanBase 數據庫中Oracle 租户PLSQL 調優的關鍵第一步,就是找到藏在程序包、存儲過程裏的慢 SQL。尤其是遇到嵌套調用的場景,手動排查堪比大海撈針。今天分享2個實戰方法,幫你快速發現問題 SQL,為後續調優節省時間!
一、DBMS_PROFILER
逐行追蹤,鎖定存過內慢 SQL 位置
DBMS_PROFILER 是 Oracle 自帶的性能剖析工具,能記錄 PLSQL 每一行代碼的執行詳情,並將結果彙總起來,詳細展示 PL 執行過程中每一條語句的執行時間。直接定位慢 SQL 在存儲過程中的具體行號。
例如當我們需要分析當前這個存過中哪裏消耗的時間較多導致整個存過執行時間變慢。
DECLARE
v_1 VARCHAR2(100);
...
v_3 VARCHAR2(100);
BEGIN
CHS_TOA_TASK_PACKAGE.IS_HAS_MATCHED(?,?,v_1,v_2,v_3);
END;
可以通過如下步驟:
- 啓動性能剖析器,備註任務名方便後續查詢
CALL dbms_profiler.start_profiler(run_comment => '任務名' || SYSDATE);
- 執行存過
- 執行完成後,停止性能剖析器
call DBMS_PROFILER.stop_profiler();
- 查看本次剖析的 runid
select * from PLSQL_PROFILER_RUNS WHERE run_comment='任務名';
- 將任務的runid帶入一下查看存過的時間消耗
select
a.runid,
a.unit_number,
a.unit_type,
a.unit_name,
b.line#,
b.total_occur,
b.total_ttime/1000000 as total_time_ms,
b.min_time as min_time_ns,
b.max_time as max_time_ns
from PLSQL_PROFILER_UNITS a,PLSQL_PROFILER_DATA b where a.runid=b.runid and a.unit_number=b.unit_number and a.runid=? order by total_time_ms desc fetch first 100 rows only;
如下圖,unit_name表示調用的存過名稱,line#表示在這個存過內的哪一行,total_occur(執行次數),total_time_ms(總耗時),可以通過這4個字段判斷出存過執行到結束,那條sql執行耗時最大,從而定位。
二、gv$ob_sql_audit
會話級採集,快速篩選高消耗 SQL
操作步驟
- 新建獨立會話窗口,通過以下sql獲取當前會話id,(避免採集無關 SQL):
select sys_context('userenv','sid') from dual;
- 在當前會話執行存過
- 通過會話id採集存過執行的性能消耗
select sql_id,to_char(substr(query_sql,1,80)),plan_id,round(avg(elapsed_time),2),sum(elapsed_time) sum ,count(*),PL_TRACE_ID from gv$ob_sql_audit where sid=? and user_name=? group by sql_id,plan_id, to_char(substr(query_sql,1,80)),PL_TRACE_ID order by sum;
參考結果如下,會詳細列出所有sql的執行時間消耗,從而定位慢SQL,但缺點是無法知道sql在存過調用中的哪一位置。所以需要配合上面DBMS_PROFILER方式。
三、實戰總結
- 想精準定位慢 SQL 在存過中的行號:直接用 DBMS_PROFILER;
- 想快速篩選會話內高消耗 SQL:先用 gv$ob_sql_audit 做初步排查;
- 嵌套程序包場景:兩者結合使用,效率翻倍,後續着重分析問題sql。
這兩個方法覆蓋了OceanBase 數據庫Oracle 租户 PL 調優中慢 SQL 定位的核心場景,代碼可直接複製套用。如果你也遇到 PLSQL 執行慢的問題,或是有獨到的優化經驗,歡迎在評論區留言分享,下次見!
更多技術分享可掃碼關注查看