PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 14.15 » Langage SQL » Requêtes parallélisées » Quand la parallélisation des requêtes peut-elle être utilisée ?

15.2. Quand la parallélisation des requêtes peut-elle être utilisée ?

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.

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 possible, dans l'absolu, 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 se vérifie :

  • 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. Il existe des exceptions : les commandes suivantes qui créent une nouvelle table et la remplissent. Un plan parallélisé peut être utilisé pour le SELECT sous-jacent de la requête :

    • CREATE TABLE ... AS

    • SELECT INTO

    • CREATE MATERIALIZED VIEW

    • REFRESH MATERIALIZED VIEW

  • 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 non sûre). La plupart des fonctions systèmes sont PARALLEL SAFE (à parallélisation sûre), mais les fonctions utilisateurs sont marquées PARALLEL UNSAFE par défaut. Voir la discussion de Section 15.4.

  • 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 qu'une seule requête utilise un très grand nombre de processus.

Même quand un plan parallélisé est généré pour une requête donnée, certaines 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 de la limitation sur le nombre total de background workers, due au paramètre max_worker_processes.

  • Aucun background worker ne peut être obtenu à cause de la limitation sur le nombre total de background workers, démarrés dans le cadre de requêtes parallèles, qui ne peut pas dépasser max_parallel_workers.

  • Le client envoie un message Execute avec un nombre de lignes à 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 ne peut survenir qu'en utilisant un client qui ne se base pas sur la libpq. Si cela arrive fréquemment, ce pourrait être une bonne idée de configurer max_parallel_workers_per_gather à zéro pour les sessions concernées, pour éviter de générer des plans de requêtes non optimaux s'ils sont exécutés de façon sérialisée.