Documentation PostgreSQL 9.6.24 > Langage SQL > Requêtes parallélisées > Quand la parallélisation des requêtes peut-elle être utilisée ? | |
Requêtes parallélisées | Plans parallélisés |
Il existe plusieurs paramètres pouvant empêcher le planificateur de la requête de générer un plan parallélisé quelles que soient les circonstances. Pour faire en sorte que des plans parallélisés puissent être générés, les paramètres suivants doivent être configurés ainsi :
max_parallel_workers_per_gather doit être configuré à une valeur strictement positive. Ceci est un cas spécial du principe plus général qu'il n'y aura pas plus de workers que le nombre configuré via max_parallel_workers_per_gather.
dynamic_shared_memory_type doit être configuré à une valeur autre que none. Les requêtes parallélisées nécessitent de la mémoire partagée dynamique pour fournir des données entre les processus participant à la parallélisation.
De plus, le système ne doit pas fonctionner en mode mono-utilisateur. Comme le système de bases de données entier fonctionne alors avec un seul processus, aucun background worker ne sera disponible.
Même quand il est habituellement possible de générer des plans pour des requêtes parallélisées, le planificateur n'en générera pas pour une requête donnée si une des conditions suivantes est remplie :
La requête écrit des données ou verrouille des lignes de la base. Si une requête contient une opération de modification de données, soit au niveau supérieur, soit dans une CTE, aucun plan parallèle ne peut être généré pour cette requête. Ceci est une limitation de l'implémentation actuelle qui pourrait être supprimée dans une prochaine version.
La requête est susceptible d'être suspendue durant l'exécution. Dans des situations où le système pense qu'une exécution pourrait être partielle ou incrémentale, aucun plan parallèle n'est généré. Par exemple, un curseur créé avec DECLARE CURSOR n'utilisera jamais un plan parallélisé. De façon similaire, une boucle PL/pgsql de la forme FOR x IN query LOOP .. END LOOP n'utilisera jamais un plan parallélisé, car le système est incapable de vérifier que le code dans la boucle peut s'exécuter en toute sécurité avec une requête parallélisée.
La requête utilise une fonction marquée PARALLEL UNSAFE (à parallélisation sûre). La plupart des fonctions systèmes sont PARALLEL SAFE, mais les fonctions utilisateurs sont marquées PARALLEL UNSAFE par défaut. Voir la discussion de Section 15.4, « Sécurité sur la parallélisation ».
La requête est exécutée à l'intérieur d'une autre requête qui est déjà parallélisée. Par exemple, si une fonction appelée par une requête parallélisée exécute elle-même une requête SQL, celle-ci n'utilisera jamais un plan parallélisé. Ceci est une limitation de l'implémentation actuelle mais il ne serait pas forcément souhaitable de la supprimer car cela pourrait mener à ce que des requêtes simple utilisent un très grand nombre de processus.
Le niveau d'isolation de la transaction est serializable. Ceci est une limitation de l'implémentation actuelle.
Même quand un plan parallélisé est généré pour une requête donnée, différentes circonstances rendront impossible l'exécution en parallèle. Si cela arrive, le leader exécutera tout seul la portion du plan sous le nœud Gather, pratiquement comme s'il n'était pas là. Ceci surviendra si une des conditions suivantes est vérifiée :
Aucun background worker ne peut être obtenu à cause d'une limitation sur le nombre total de background workers, due au paramètre max_worker_processes.
Le client envoie un message Execute avec un nombre à récupérer différent de zéro. Voir la discussion sur le protocole de requête étendu. Comme la bibliothèque libpq ne fournit actuellement aucun moyen pour envoyer ce type de message, cela peut seulement survenir suite à l'utilisation d'un client qui ne se base pas sur la libpq. Si cela arrive fréquemment, il pourrait être une bonne idée de configurer max_parallel_workers_per_gather pour les sessions où cela pourrait survenir, pour éviter de générer des plans de requêtes non optimales s'ils sont exécutés de façon sérialisé.
Une requête préparée est exécutée en utilisant une instruction CREATE TABLE .. AS EXECUTE ... Cette construction convertit ce qui serait autrement une opération en lecture seule en une opération en lecture/écriture, la rendant ainsi inutilisable pour une requête parallélisée.
Le niveau de transaction est serializable. Cette situation ne doit normalement pas survenir car des plans de requêtes parallélisés ne sont pas générés dans une transaction serializable. Néanmoins, il peut arriver que le niveau d'isolation de la transaction soit modifié après la génération du plan et avant son exécution.