本文介紹了自定義函數的執行原理及使用方法。
原理介紹
創建成功的自定義函數,會被持久化到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對調用深度進行限制,因為過深的調用不利于理解自定義函數的執行邏輯,同時會導致大量資源的占用。