當PL/SQL函數或預存程序變得複雜時,您可能會發現難以定位其中的效能瓶頸。POLAR_PLSQL_PROFILER外掛程式能夠監控並記錄PL/SQL代碼的執行細節,協助您精確分析每一行代碼的執行耗時和函數間的調用關係,從而有效地進行效能最佳化。
功能簡介
POLAR_PLSQL_PROFILER是一個效能分析工具,它通過掛載到PL/SQL的執行引擎上,在代碼運行時採集效能資料。這些資料包括每行代碼的執行次數、累計耗時,以及函數之間的調用層級和時間分布。分析器將採集到的資料存放區在當前會話的記憶體中,您可以通過調用其提供的函數,以結構化資料或可視化HTML報告的形式查看分析結果。
適用範圍
支援的PolarDB PostgreSQL版(相容Oracle)的版本: Oracle文法相容 2.0,且核心小版本需為2.0.14.19.40.0及以上。
優勢
程式碼級分析:能夠精確到每一行原始碼的執行次數和耗時,快速定位熱點代碼。
調用圖譜:清晰展示函數間的調用關係,協助理解整體耗時在不同函數模組間的分布。
可視化報告:支援一鍵產生內容詳盡的HTML報告,便於分析和分享。
注意事項
效能開銷:開啟效能分析會帶來額外的效能開銷,建議僅在開發或效能診斷情境中使用,避免在生產環境中長時間開啟。
會話層級:分析器採集的資料僅在當前資料庫會話中有效。會話斷開後,所有分析資料將丟失。
及時清理:分析結束後,請及時禁用分析器並清理資料,以釋放資源並消除效能影響。
操作指南
為了更好地展示工具的使用,以下將通過兩個樣本進行講解:一個用於快速入門,另一個用於示範如何分析包含子函數調用的複雜情境。
快速入門與基本分析
本樣本將引導您完成一次最基本的效能分析流程。
步驟一:安裝外掛程式
在使用前,請先建立外掛程式並啟用分析器。分析器將開始監控當前會話中所有PL/SQL代碼的執行。
-- 建立外掛程式(如果尚未建立)
CREATE EXTENSION polar_plsql_profiler;步驟二:準備範例程式碼
執行您需要分析效能的PL/SQL函數或預存程序。以下是一個樣本函數:
-- 建立一個用於測試的函數
CREATE OR REPLACE FUNCTION simple_test_func(p_times IN NUMBER)
RETURNS VARCHAR2 AS
v_result VARCHAR2(100);
BEGIN
FOR i IN 1 .. p_times LOOP
v_result := 'Iteration ' || i;
END LOOP;
RETURN v_result;
END;步驟三:啟用分析器
啟動分析器,啟用成功將返回t。
SELECT plsql_profiler_enable();步驟四:執行目標代碼
執行函數以收集資料。
SELECT simple_test_func(100);步驟五:分析效能資料
可以通過多種方式查看採集到的效能資料。
查看函數調用概覽
使用plsql_profiler_show_funclist()函數可以查看本次分析中所有被調用函數的總體效能統計,協助您快速識別耗時最長的函數。
SELECT * FROM plsql_profiler_show_funclist();返回結果如下:
func_call | func_oid_list | call_count | us_total | us_declare | us_children | us_self | time_stamp
--------------------------------------+---------------+------------+----------+------------+-------------+---------+-------------------------------
oid=21749 public.simple_test_func() | {21749} | 1 | 303 | 13 | 0 | 303 | 2026-01-05 06:01:20.619468+00查看指定函數的行級詳情
當定位到目標函數後,使用plsql_profiler_show_function()可以查看該函數內部每一行代碼的詳細效能資料。
-- 首先,從函數列表中擷取目標函數的OID數組(func_oid_list)
-- 然後,將該OID數組作為參數傳入以下函數
SELECT * FROM plsql_profiler_show_function(ARRAY['...']); -- 請將'...'替換為函數OID列表樣本
SELECT * FROM plsql_profiler_show_function(ARRAY[21749]);返回結果如下:
line_number | exec_count | total_time | percent | avg_time | min_time | max_time | source_code | time_stamp
-------------+------------+------------+---------+----------+----------+----------+----------------------------------------+------------
0 | 1 | 303 | 100 | 303 | 303 | 303 | ---- Function Totals ---- |
1 | 0 | 0 | 0 | 0 | 0 | 0 | v_result VARCHAR2(100); |
2 | 1 | 287 | 94.72 | 287 | 287 | 287 | BEGIN |
3 | 1 | 276 | 91.09 | 276 | 276 | 276 | FOR i IN 1 .. p_times LOOP |
4 | 100 | 145 | 47.85 | 1 | 0 | 145 | v_result := 'Iteration ' || i; |
5 | 0 | 0 | 0 | 0 | 0 | 0 | END LOOP; |
6 | 1 | 0 | 0 | 0 | 0 | 0 | RETURN v_result; |
7 | 0 | 0 | 0 | 0 | 0 | 0 | END; | 步驟六:清理資源
分析工作完成後,執行以下操作來重設資料、禁用分析器並移除外掛程式,以避免對後續操作產生效能影響。
-- 1. (可選)重設已採集的分析資料
SELECT plsql_profiler_reset();
-- 2. 禁用分析器
SELECT plsql_profiler_disable();
-- 3. (可選)如果不再需要,可以刪除外掛程式
DROP EXTENSION polar_plsql_profiler;深入分析與定位瓶頸(含子函數調用)
本樣本將類比一個更真實的情境:一個主函數調用一個耗時的子函數。我們將示範如何通過分析器找到真正的效能瓶頸。
步驟一:安裝外掛程式
在使用前,請先建立外掛程式並啟用分析器。分析器將開始監控當前會話中所有PL/SQL代碼的執行。
-- 建立外掛程式(如果尚未建立)
CREATE EXTENSION polar_plsql_profiler;步驟二:準備範例程式碼
首先,建立一個包含子函數的複雜包。
-- 建立包含子函數的複雜包
CREATE OR REPLACE PACKAGE complex_pkg AS
FUNCTION calculate_tax(p_salary NUMBER) RETURN NUMBER;
PROCEDURE process_payroll(p_dept_id NUMBER);
END complex_pkg;
CREATE OR REPLACE PACKAGE BODY complex_pkg AS
FUNCTION calculate_tax(p_salary NUMBER) RETURN NUMBER IS
v_tax_amount NUMBER;
-- 子函數
FUNCTION get_tax_rate(p_income NUMBER) RETURN NUMBER IS
v_rate NUMBER;
BEGIN
IF p_income <= 50000 THEN
v_rate := 0.10;
ELSIF p_income <= 100000 THEN
v_rate := 0.20;
ELSE
v_rate := 0.30;
END IF;
RETURN v_rate;
END get_tax_rate;
BEGIN
v_tax_amount := p_salary * get_tax_rate(p_salary);
RETURN v_tax_amount;
END calculate_tax;
PROCEDURE process_payroll(p_dept_id NUMBER) IS
BEGIN
-- 執行一些操作
NULL;
END process_payroll;
END complex_pkg;步驟三:啟用分析器
啟動分析器,啟用成功將返回t。
SELECT plsql_profiler_enable();步驟四:執行目標代碼
執行函數以收集資料。
SELECT complex_pkg.calculate_tax(75000);步驟五:分析效能資料
可以通過多種方式查看採集到的效能資料。
查看函數調用概覽
使用plsql_profiler_show_funclist()函數可以查看本次分析中所有被調用函數的總體效能統計,協助您快速識別耗時最長的函數。
SELECT * FROM plsql_profiler_show_funclist();返回結果如下:
func_call | func_oid_list | call_count | us_total | us_declare | us_children | us_self | time_stamp
---------------------------------------------+--------------------+------------+----------+------------+-------------+---------+-------------------------------
oid=0 inline_code_block | {0} | 1 | 24 | 19 | 0 | 24 | 2026-01-05 04:03:37.68941+00
oid=21721 complex_pkg.calculate_tax() | {21721} | 1 | 1309 | 8 | 815 | 494 | 2026-01-05 04:03:37.689697+00
oid=21721 complex_pkg.calculate_tax() +| {21721,4294957297} | 1 | 815 | 9 | 0 | 815 | 2026-01-05 04:03:37.690177+00
oid=4294957297 -> public.get_tax_rate() | | | | | | |
(3 rows)查看指定函數的行級詳情
當定位到目標函數後,使用plsql_profiler_show_function()可以查看該函數內部每一行代碼的詳細效能資料。
-- 首先,從函數列表中擷取目標函數的OID數組(func_oid_list)
-- 然後,將該OID數組作為參數傳入以下函數
SELECT * FROM plsql_profiler_show_function(ARRAY['...']); -- 請將'...'替換為函數OID列表樣本
SELECT * FROM plsql_profiler_show_function(ARRAY[21721,4294957297]);返回結果如下:
line_number | exec_count | total_time | percent | avg_time | min_time | max_time | source_code | time_stamp
-------------+------------+------------+---------+----------+----------+----------+-------------------------------------------+------------
0 | 1 | 351 | 100 | 351 | 351 | 351 | ---- Function Totals ---- |
1 | 0 | 0 | 0 | 0 | 0 | 0 | v_rate NUMBER; |
2 | 1 | 340 | 96.87 | 340 | 340 | 340 | BEGIN |
3 | 1 | 338 | 96.3 | 338 | 338 | 338 | IF p_income <= 50000 THEN |
4 | 0 | 0 | 0 | 0 | 0 | 0 | v_rate := 0.10; |
5 | 0 | 0 | 0 | 0 | 0 | 0 | ELSIF p_income <= 100000 THEN |
6 | 1 | 24 | 6.84 | 24 | 24 | 24 | v_rate := 0.20; |
7 | 0 | 0 | 0 | 0 | 0 | 0 | ELSE |
8 | 0 | 0 | 0 | 0 | 0 | 0 | v_rate := 0.30; |
9 | 0 | 0 | 0 | 0 | 0 | 0 | END IF; |
10 | 1 | 0 | 0 | 0 | 0 | 0 | RETURN v_rate; |
11 | 0 | 0 | 0 | 0 | 0 | 0 | END get_tax_rate; | 查看函數的行級效能資料
使用plsql_profiler_show_funclist()和plsql_profiler_show_function()函數可以聯集查詢所有函數內部每一行代碼的詳細效能資料。
SELECT * FROM plsql_profiler_show_funclist() F
CROSS JOIN LATERAL plsql_profiler_show_function(F.func_oid_list) C;步驟六:產生並查看HTML報告
為了更直觀地分析,您可以使用plsql_profiler_get_report()產生一份完整的HTML格式報告。
-- 在psql用戶端中,使用\o命令將輸出重新導向到檔案
\o plsql_profiler_report.html
-- 開啟僅顯示元組模式,以便輸出純淨的HTML內容
\t
-- 產生報告
SELECT plsql_profiler_get_report('My Performance Report');
-- 關閉重新導向
\o
-- 關閉僅顯示元組模式
\t 執行完成後,將返回一個包含完整報告內容的HTML字串。請將該字串複製到HTML檔案中,並在瀏覽器中開啟,以便查看詳盡的效能分析報告。
步驟七:清理資源
分析工作完成後,執行以下操作來重設資料、禁用分析器並移除外掛程式,以避免對後續操作產生效能影響。
-- 1. (可選)重設已採集的分析資料
SELECT plsql_profiler_reset();
-- 2. 禁用分析器
SELECT plsql_profiler_disable();
-- 3. (可選)如果不再需要,可以刪除外掛程式
DROP EXTENSION polar_plsql_profiler;相關函數參考
下表列出了POLAR_PLSQL_PROFILER外掛程式提供的核心函數。
控制函數
plsql_profiler_enable()
說明:在當前會話中啟用效能分析器。
文法:
sys.plsql_profiler_enable() RETURNS bool傳回值:
bool類型。啟用成功返回true,否則返回false。
plsql_profiler_disable()
說明:在當前會話中禁用效能分析器。
文法:
sys.plsql_profiler_disable() RETURNS bool傳回值:
bool類型。禁用成功返回true,否則返回false。
plsql_profiler_reset()
說明:清除當前會話中已收集的所有效能分析資料。
文法:
sys.plsql_profiler_reset() RETURNS void傳回值:無。
報告與分析函數
plsql_profiler_show_funclist()
說明:顯示所有被調用函數的調用鏈和總體效能摘要,不包含分析器自身的函數。
文法:
sys.plsql_profiler_show_funclist() RETURNS TABLE(...)傳回值:返回一個表,包含如下欄位。
欄位
說明
func_call函數調用鏈(文本)。
func_oid_list調用棧中的函數OID列表。
call_count函數被調用的次數。
us_total總執行時間(微秒)。
us_declare聲明部分的執行時間(微秒)。
us_children子函數的執行時間(微秒)。
us_self函數自身的執行時間(微秒)。
time_stamp函數調用的時間戳記。
plsql_profiler_show_function()
說明:顯示指定函數內每一行代碼的詳細效能統計。
文法:
sys.plsql_profiler_show_function(func_oid OID[]) RETURNS TABLE(...)參數說明:
參數
說明
func_oid要顯示詳細資料的函數OID數組,可從
plsql_profiler_show_funclist()的func_oid_list列擷取。傳回值:返回一個表,包含如下欄位。
欄位
說明
line_number原始碼中的行號。
exec_count此行被執行的次數。
total_time總執行時間(微秒)。
percent此行在函數總時間中所佔百分比。
avg_time每次執行的平均時間(微秒)。
min_time此行的最小執行時間(微秒)。
max_time此行的最大執行時間(微秒)。
source_code此行的原始碼。
time_stamp執行匿名塊的時間戳記,對於非匿名塊為
null。
plsql_profiler_get_report()
說明:產生一份完整的HTML格式效能分析報告。
文法:
sys.plsql_profiler_get_report(IN title text DEFAULT 'PL/SQL PROFILER REPORT') RETURNS text參數說明:
參數
說明
title報告的標題,選擇性參數,預設為
PL/SQL PROFILER REPORT。傳回值:
text類型。返回包含完整報告內容的HTML字串。
底層資料擷取函數
plsql_profiler_linestats_local()
說明:擷取原始的行級統計資訊,包括函數執行次數和計時詳情。
文法:
sys.plsql_profiler_linestats_local() RETURNS SETOF record傳回值:返回一個記錄集,包含如下欄位。
欄位
說明
func_oid函數OID數組,表示呼叫堆疊。
line_number原始碼中的行號。
exec_count此行被執行的次數。
total_time總執行時間(微秒)。
percent此行在函數總時間中所佔百分比。
min_time此行的最小執行時間(微秒)。
max_time此行的最大執行時間(微秒)。
source此行的原始碼。
time_stamp匿名塊的時間戳記。
plsql_profiler_callgraph_local()
說明:擷取原始的函數調用圖資訊,包括函數調用次數和計時。
文法:
sys.plsql_profiler_callgraph_local() RETURNS SETOF record傳回值:返回一個記錄集,包含如下欄位。
欄位
說明
stack函數OID數組,表示呼叫堆疊。
call_count此函數被調用的次數。
us_total總執行時間(微秒)。
us_declare在聲明部分花費的時間(微秒)。
us_children在子函數中花費的時間(微秒)。
us_self在此函數本身中花費的時間(微秒)。
time_stamp函數調用的時間戳記。
plsql_profiler_func_oids_local()
說明:擷取所有被分析過的函數的OID數組。
文法:
sys.plsql_profiler_func_oids_local() RETURNS oid[]傳回值:
oid[]類型。返回一個包含所有被採集過資訊的函數OID的數組。
plsql_profiler_funcs_source()
說明:根據函數OID數組返回其原始碼。
文法:
sys.plsql_profiler_funcs_source(func_oids oid[]) RETURNS SETOF record參數說明:
參數
說明
func_oid要擷取原始碼的函數OID數組,可從
plsql_profiler_linestats_local()的func_oid列擷取。傳回值:返回一個記錄集,包含如下欄位。
欄位
說明
func_oid函數OID。
line_number原始碼中的行號。
source此行的原始碼。
plsql_profiler_get_stack()
說明:將函數OID堆棧轉換為函數簽名數組。
文法:
sys.plsql_profiler_get_stack(stack oid[]) RETURNS text[]參數說明:
參數
說明
stack函數OID數組,表示呼叫堆疊。可從
plsql_profiler_callgraph_local()的stack列擷取。傳回值:
text[]類型。返回一個包含函數簽名的文本數組。
plsql_profiler_get_stack_formatted()
說明:將函數OID堆棧轉換為格式化的調用鏈和OID列表。
文法:
sys.plsql_profiler_get_stack_formatted(stack oid[]) RETURNS text[]參數說明:
參數
說明
stack函數OID數組,表示呼叫堆疊。可從
plsql_profiler_callgraph_local()的stack列擷取。傳回值:
text[]類型。返回包含格式化函數調用鏈和OID列表的文本數組。