Documentation PostgreSQL 14.22 » Langage SQL » Requêtes parallélisées » Sécurité de la parallélisation

Précédent | Niveau supérieur | Suivant
15.3. Plans parallélisés | Sommaire | Partie III. Administration du serveur

## 15.4. Sécurité de la parallélisation

Le planificateur classifie les opérations impliquées dans une requête comme étant à parallélisation sûre, parallélisation restreinte, ou parallélisation non sûre. Une opération à parallélisation sûre est une opération n'entrant pas en conflit avec une requête parallélisée. Une opération à parallélisation restreinte ne peut pas être exécutée par un worker parallélisé, mais peut l'être par le leader pendant l'exécution. De ce fait, les opérations à parallélisation restreinte ne peuvent jamais survenir sous un nœud `Gather` ou `Gather Merge`. Une opération à parallélisation non sûre ne peut être exécutée dans une requête parallélisée, y compris au niveau du leader. Quand une requête contient quoi que ce soit de non sûr à paralléliser, la parallélisation y est complètement désactivée.

Les opérations suivantes sont toujours à parallélisation restreinte.

- Parcours de CTE (Common Table Expressions).

- Parcours de tables temporaires.

- Parcours de tables externes, sauf si le wrapper de données distantes a une API `IsForeignScanParallelSafe` qui indique le contraire.

- Nœuds du plan pour lesquels un `InitPlan` est attaché.

- Nœuds du plan qui référencent un `SubPlan` corrélé.

### 15.4.1. Marquage de parallélisation pour les fonctions et agrégats

Le planificateur ne peut pas déterminer automatiquement si une fonction ou un agrégat définis par un utilisateur est à parallélisation sûre, restreinte ou non sûre, car cela nécessiterait de pouvoir prédire chaque opération réalisable par la fonction. En général, c'est équivalent au problème de l'arrêt et de ce fait, impossible. Même pour des fonctions simples où cela pourrait se faire, nous n'essayons pas, car ce serait coûteux et sujet à erreurs. À la place, toutes les fonctions définies par des utilisateurs sont supposées à parallélisation non sûre sauf indication contraire. Lors de l'utilisation des instructions CREATE FUNCTION et ALTER FUNCTION, un marquage est possible en spécifiant `PARALLEL SAFE`, `PARALLEL RESTRICTED` ou `PARALLEL UNSAFE` suivant ce qui est approprié. Lors de l'utilisation de CREATE AGGREGATE, l'option `PARALLEL` peut être spécifiée comme `SAFE`, `RESTRICTED` ou `UNSAFE`.

Les fonctions et agrégats doivent être marqués `PARALLEL UNSAFE` s'ils écrivent dans la base, accèdent à des séquences, modifient l'état de la transaction même temporairement (par exemple, une fonction PL/pgSQL qui définit un bloc `EXCEPTION` pour récupérer des erreurs), ou font des modifications persistantes sur les paramètres. De façon similaire, les fonctions doivent être marquées `PARALLEL RESTRICTED` si elles accèdent à des tables temporaires, à l'état de connexion du client, à des curseurs, à des requêtes préparées ou à un quelconque état local du processus serveur que le système ne peut pas synchroniser entre les différents workers. Par exemple, `setseed` et `random` sont à parallélisation restreinte pour cette dernière raison.

En général, si une fonction est marquée comme étant sûre alors qu'elle ne l'est pas, ou si elle est marquée restreinte alors que sa parallélisation en fait n'est pas sûre, elle peut être cause d'erreurs ou de réponses fausses lors de l'utilisation dans une requête parallélisée. Les fonctions en langage C peuvent en théorie avoir des comportements indéfinis en cas de mauvais marquage, car le système n'a aucun moyen de se défendre contre du code C arbitraire. Cela étant dit, dans la plupart des cas, le résultat ne sera pas pire qu'avec toute autre fonction. En cas de doute, le mieux est probablement de marquer les fonctions en tant que `UNSAFE`.

Si une fonction exécutée avec un worker parallèle acquiert des verrous non détenus par le leader, par exemple en exécutant une requête sur une table non référencée dans la requête, ces verrous seront relâchés à la sortie du worker, et non pas à la fin de la transaction. Si vous écrivez une fonction qui fait cela et que cette différence de comportement a une importance pour vous, marquez ces fonctions comme `PARALLEL RESTRICTED` pour vous assurer qu'elles ne s'exécutent qu'au sein du leader.

Notez que le planificateur de requêtes ne cherche pas à différer l'évaluation des fonctions ou agrégats à parallélisation restreinte impliqués dans la requête pour obtenir un meilleur plan. Donc, par exemple, si une clause `WHERE` appliquée à une table particulière est à parallélisation restreinte, le planificateur ne tentera pas de placer le parcours de cette table dans une portion parallélisée du plan. Dans certains cas, il serait possible (voire efficace) d'inclure le parcours de cette table dans la partie parallélisée de la requête et de différer l'évaluation de la clause `WHERE` afin qu'elle se déroule au-dessus du nœud `Gather`. Néanmoins, le planificateur ne le fait pas.