本文介紹了自訂函數的執行原理及使用方法。
原理介紹
建立成功的自訂函數,會被持久化到Meta center中,按需載入到計算節點中執行。SQL相關的執行邏輯會發送到SQL engine中執行,然後擷取執行結果,控制流程程等相關的邏輯會在PL engine中執行。
自訂函數在真正執行前會註冊到運行時函數管理中心,同時整個執行過程中單條Query的記憶體大小會被嚴格限制。
函數下推
PolarDB-X通過識別SQL DATA ACCESS欄位,來判斷是否需要將該自訂函數在DN上進行註冊,若且唯若SQL DATA ACCESS欄位為no sql時,該函數會同時在DN上進行註冊。在DN上註冊後,該函數便具備了在DN上執行的條件,即該自訂函數可被下推。
為了保持和MySQL的相容性,PolarDB-X的自訂函數均會註冊到MySQL庫中。
函數下推與擴縮容
擴容後需要手動執行pushdown udf
指令,將可下推的自訂函數在新的DN節點進行註冊。
與MySQL的區別
自訂函數中僅允許DQL,不允許DML和DDL等涉及到資料修改的操作。
MySQL的儲存函數為庫層級,PolarDB-X的自訂函數為執行個體層級。
由於涉及到自訂函數的下推邏輯,因此SQL DATA ACCESS欄位不允許修改。
注意事項
5.4.16及以上版本支援此功能。
文法
建立自訂函數
CREATE
[DEFINER = user]
FUNCTION sp_name ([func_parameter[,...]])
RETURNS type
[characteristic ...] routine_body
func_parameter:
param_name type
characteristic:
COMMENT 'string'
| LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
routine_body:
Valid SQL routine statement
樣本
CREATE FUNCTION my_mul(x int, y int)
RETURNS int
LANGUAGE SQL
DETERMINISTIC
COMMENT 'my multiply function'
RETURN x*y*31;
調用自訂函數
自訂函數與普通的系統內建函數調用方法一致。
刪除自訂函數
DROP FUNCTION [IF EXISTS] FUNCTION_NAME;
修改自訂函數
ALTER FUNCTION func_name [characteristic ...]
characteristic: {
COMMENT 'string'
| LANGUAGE SQL
| SQL SECURITY { DEFINER | INVOKER }
}
查看所有已定義的自訂函數
SELECT * FROM information_schema.Routines WHERE ROUTINE_TYPE = 'FUNCTION';
查看某個特定的自訂函數
SHOW FUNCTION STATUS [LIKE 'pattern' | WHERE expr]
SHOW CREATE FUNCTION 函數名;
SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME = '函數名';
查看已下推的自訂函數
SELECT * FROM information_schema.pushed_function;
取消正在執行的自訂函數
使用kill命令結束正在執行的查詢即可。
kill {query | connection} connection_id;
自訂函數緩衝管理
自訂函數的所有元資訊,即是否存在某自訂函數,始終會在緩衝中,但具體的函數體僅會在需要時被載入。
查看緩衝條目
select * from information_schema.function_cache;
查看緩衝容量
select * from information_schema.function_cache_capacity;
設定緩衝大小
resize function cache num;
清空緩衝
clear function cache;
重新載入自訂函數
reload functions;
樣本
# 開始建立自訂函數
CREATE FUNCTION my_mul(x int, y int)
RETURNS int
LANGUAGE SQL
DETERMINISTIC
COMMENT 'my multiply function'
RETURN x*y*31;
# 此時未進行任何調用,查看function_cache,發現cache中已包含該function
# 而size為0,說明並沒有真正進行載入
select * from information_schema.function_cache;
+--------------------+--------------+------+
| ID | FUNCTION | SIZE |
+--------------------+--------------+------+
| xx.xx.xx.xx:3000 | mysql.my_mul | 0 |
| yy.yy.yy.yy:3100 | mysql.my_mul | 0 |
+--------------------+--------------+------+
# 調用my_mul
select my_mul(2,2);
+--------------+
| my_mul(2, 2) |
+--------------+
| 124 |
+--------------+
# 查看相關視圖,發現已經進行了載入
select * from information_schema.function_cache;
+--------------------+--------------+------+
| ID | FUNCTION | SIZE |
+--------------------+--------------+------+
| xx.xx.xx.xx:3000 | mysql.my_mul | 0 |
| yy.yy.yy.yy:3100 | mysql.my_mul | 79 |
+--------------------+--------------+------+
select * from information_schema.function_cache_capacity;
+--------------------+-----------+-------------+
| ID | USED_SIZE | TOTAL_SIZE |
+--------------------+-----------+-------------+
| xx.xx.xx.xx:3000 | 0 | 15139759718 |
| yy.yy.yy.yy:3100 | 79 | 15139759718 |
+--------------------+-----------+-------------+
# reload function後,緩衝被重設
reload functions;
# 查看相關視圖,發現已被重設
select * from information_schema.function_cache;
+--------------------+--------------+------+
| ID | FUNCTION | SIZE |
+--------------------+--------------+------+
| xx.xx.xx.xx:3000 | mysql.my_mul | 0 |
| yy.yy.yy.yy:3100 | mysql.my_mul | 0 |
+--------------------+--------------+------+
自訂函數資源管理
記憶體管理
自訂函數執行過程中的記憶體佔用主要為緩衝的Cursor,因此PolarDB-X對單個Cursor所能使用的最大記憶體以及整個自訂函數在執行時佔用的記憶體進行了限制,由參數PL_CURSOR_MEMORY_LIMIT和PL_MEMORY_LIMIT控制。同時,調用自訂函數的整個查詢語句的記憶體也會被限制。
建議PL_CURSOR_MEMORY_LIMIT的值不小於128k,即131072,同時PL_CURSOR_MEMORY_LIMIT不應當大於PL_MEMORY_LIMIT。
其中,變數PL_CURSOR_MEMORY_LIMIT用於控制每個Cursor所佔用的記憶體,超過該閾值時會溢出到硬碟中;變數PL_MEMORY_LIMIT用於控制每個自訂函數所能使用的最大記憶體。
調用深度限制
可通過參數MAX_PL_DEPTH對調用深度進行限制,因為過深的調用不利於理解自訂函數的執行邏輯,同時會導致大量資源的佔用。