Le planificateur classifie les opérations impliquées dans une requête comme étant à parallélisation sûre, restreintes, ou non sûres. 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 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.
Accès à un InitPlan ou à un SubPlan corrélé.
Le planificateur ne peut pas déterminer automatiquement si une fonction ou un agrégat défini 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éalisée 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 cela 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(7) et ALTER FUNCTION(7), 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(7), 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 persistentes 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 (et même si elle est seulement restreinte), ou si une fonction 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 à 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.