Dans PolarDB-X, les fonctions définies par l'utilisateur (UDF) sont des fonctions stockées SQL qui étendent la logique des requêtes par des calculs personnalisés.
Les UDF sont prises en charge à partir de PolarDB-X 5.4.16.
Fonctionnement

Après la création d'une UDF, PolarDB-X la stocke dans le centre de métadonnées et la charge sur les nœuds de calcul pour exécution. Cette dernière se répartit selon le type de logique :
Logique SQL : transmise au moteur SQL.
Logique de flux de contrôle : exécutée dans le moteur PL.
Avant toute exécution, chaque UDF est enregistrée auprès du centre de gestion des fonctions d'exécution. La consommation mémoire par requête est strictement limitée durant le traitement.
Pushdown de fonction
PolarDB-X examine le champ SQL DATA ACCESS d'une UDF pour déterminer s'il convient de l'enregistrer sur les nœuds de données. Seules les UDF dont le champ SQL DATA ACCESS est défini sur NO SQL sont enregistrées sur ces nœuds et peuvent faire l'objet d'un pushdown.
Pour garantir la compatibilité avec MySQL, PolarDB-X enregistre les UDF éligibles au pushdown dans la bibliothèque MySQL du nœud de données.
Le champ SQL DATA ACCESS ne peut pas être modifié, car il détermine la logique de pushdown de l'UDF.
Pushdown après mise à l'échelle
Après une mise à l'échelle, exécutez la commande pushdown udf pour enregistrer les UDF éligibles sur le nouveau nœud de données (DN).
Différences avec MySQL
Les UDF de PolarDB-X se distinguent des fonctions stockées MySQL sur trois aspects :
| Différence | MySQL | PolarDB-X |
|---|---|---|
| Opérations prises en charge | DQL, DML, DDL | DQL uniquement — les opérations DML et DDL ne sont pas autorisées au sein d'une UDF |
| Portée du stockage | Niveau base de données | Niveau instance |
Champ SQL DATA ACCESS |
Modifiable via ALTER FUNCTION |
Immuable — régit le comportement de pushdown |
Syntaxe
Création d'une UDF
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
Caractéristiques principales :
| Caractéristique | Description |
|---|---|
[NOT] DETERMINISTIC |
Indique si la fonction est déterministe : des entrées identiques produisent toujours le même résultat. Spécifiez DETERMINISTIC pour permettre l'optimisation. |
NO SQL | CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA |
Définit le champ SQL DATA ACCESS. Choisissez NO SQL pour activer le pushdown vers les nœuds de données. Ce champ est définitif après la création. |
SQL SECURITY DEFINER | INVOKER |
Détermine si la fonction s'exécute avec les privilèges de son créateur (DEFINER) ou ceux de l'appelant (INVOKER). |
Exemple :
CREATE FUNCTION my_mul(x int, y int)
RETURNS int
LANGUAGE SQL
DETERMINISTIC
COMMENT 'my multiply function'
RETURN x*y*31;
Appel d'une UDF
Appelez une UDF comme une fonction intégrée :
SELECT my_mul(2, 2);
+--------------+
| my_mul(2, 2) |
+--------------+
| 124 |
+--------------+
Modification d'une UDF
La commande ALTER FUNCTION permet de modifier les attributs COMMENT, LANGUAGE SQL et SQL SECURITY. En revanche, elle ne permet pas de changer le champ SQL DATA ACCESS.
ALTER FUNCTION func_name [characteristic ...]
characteristic: {
COMMENT 'string'
| LANGUAGE SQL
| SQL SECURITY { DEFINER | INVOKER }
}
Suppression d'une UDF
DROP FUNCTION [IF EXISTS] FUNCTION_NAME;
Consultation des UDF
Lister toutes les UDF :
SELECT * FROM information_schema.Routines WHERE ROUTINE_TYPE = 'FUNCTION';
Consulter une UDF spécifique :
SHOW FUNCTION STATUS [LIKE 'pattern' | WHERE expr]
SHOW CREATE FUNCTION function_name;
SELECT * FROM information_schema.Routines WHERE ROUTINE_NAME = 'function_name';
Afficher les UDF en pushdown :
SELECT * FROM information_schema.pushed_function;
Annulation d'une UDF en cours d'exécution
Exécutez l'instruction KILL pour interrompre une requête exécutant une UDF :
KILL {QUERY | CONNECTION} connection_id;
Gestion du cache
Les métadonnées des UDF (notamment l'existence de la fonction) résident en permanence dans le cache. Le corps de la fonction est chargé à la demande, uniquement lors du premier appel.
Commandes de gestion du cache
| Commande | Description |
|---|---|
SELECT * FROM information_schema.function_cache; |
Affiche les UDF mises en cache ainsi que leur taille chargée |
SELECT * FROM information_schema.function_cache_capacity; |
Indique l'espace cache utilisé et total par nœud |
RESIZE FUNCTION CACHE num; |
Redimensionne la capacité du cache |
CLEAR FUNCTION CACHE; |
Vide intégralement le cache |
RELOAD FUNCTIONS; |
Recharge l'ensemble des UDF et réinitialise le cache |
Exemple de cycle de vie du cache
L'exemple suivant illustre le cycle de vie complet du cache pour la fonction my_mul.
-- Create the UDF.
CREATE FUNCTION my_mul(x int, y int)
RETURNS int
LANGUAGE SQL
DETERMINISTIC
COMMENT 'my multiply function'
RETURN x*y*31;
-- The function exists in cache, but the body is not loaded yet (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 |
+--------------------+--------------+------+
-- Call the UDF. This triggers the function body to load on one node.
SELECT my_mul(2, 2);
+--------------+
| my_mul(2, 2) |
+--------------+
| 124 |
+--------------+
-- The body is now loaded on the node that executed the call (SIZE = 79).
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 the UDF to reset the cache on all nodes.
RELOAD FUNCTIONS;
-- All nodes show SIZE = 0 again.
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 |
+--------------------+--------------+------+
Gestion des ressources
Limites mémoire
Lors de l'exécution d'une UDF, la mémoire est principalement consommée par les curseurs. Configurez les paramètres suivants pour définir les plafonds mémoire :
| Paramètre | Description |
|---|---|
PL_CURSOR_MEMORY_LIMIT |
Mémoire maximale allouée à un curseur unique. Au-delà de ce seuil, les données débordent sur le disque. La valeur minimale recommandée est de 128 Ko (131072). |
PL_MEMORY_LIMIT |
Enveloppe mémoire globale pour une UDF. Doit être supérieure ou égale à PL_CURSOR_MEMORY_LIMIT. |
La mémoire allouée à la requête globale appelant l'UDF est également limitée.
Profondeur d'appel maximale
Le paramètre MAX_PL_DEPTH permet de limiter la profondeur d'appel des UDF. Des piles d'appels trop profondes compliquent le débogage et consomment des ressources importantes.