Améliorer les performances d'INSERT SELECT avec SELECT parallèle

L'exécution parallèle de la partie SELECT d'une requête INSERT INTO ... SELECT peut améliorer les performances des requêtes AlloyDB pour PostgreSQL, en particulier pour les tables partitionnées et les requêtes complexes.

En parallélisant le sous-plan SELECT, la base de données utilise plusieurs processus de nœud de calcul pour récupérer les données. La base de données insère ensuite les données récupérées dans la table cible. Cette division du travail peut améliorer les performances de la base de données.

Fonctionnement des plans de requêtes parallèles dans PostgreSQL

Dans PostgreSQL, l'optimiseur de requêtes peut créer un plan parallèle pour une requête entière ou une partie d'une requête. Lorsqu'un plan parallèle est généré, un nœud Gather ou Gather Merge est ajouté en haut du plan.

Ce nœud coordonne plusieurs processus de nœud de calcul parallèles. Chaque nœud de calcul exécute une partie de la tâche, par exemple en analysant une partie d'une table. Le nœud Gather collecte ensuite les résultats de tous les nœuds de calcul et les transmet à l'étape suivante de la requête ou au client.

Par exemple, le plan de requête suivant montre un nœud Gather qui prévoit d'utiliser cinq processus de nœud de calcul pour une analyse séquentielle parallèle sur la table t1.

EXPLAIN SELECT * FROM t1;

                  QUERY PLAN
-------------------------------------------------------------
 Gather  (cost=0.00..143359.76 rows=9999878 width=60)
   Workers Planned: 5
   ->  Parallel Seq Scan on t1  (cost=0.00..143359.76 rows=1999976 width=60)
(3 rows)

Exécution parallèle des instructions INSERT…SELECT

AlloyDB améliore les performances de INSERT INTO ... SELECT en utilisant plusieurs processus de calcul pour paralléliser l'instruction SELECT. Cette répartition des tâches peut améliorer les performances de la base de données. La requête doit être compatible avec le traitement parallèle et ne doit comporter aucune condition qui empêche la parallélisation.

De nombreuses opérations de base de données utilisent des instructions INSERT INTO ... SELECT pour ajouter des lignes à une table. Souvent, la partie SELECT de l'instruction est la partie la plus gourmande en ressources de la requête.

La fonctionnalité est contrôlée par les paramètres de configuration suivants :

  • enable_parallel_select_for_insert_select : active ou désactive la fonctionnalité . Ce paramètre est activé par défaut dans PostgreSQL 14 et versions ultérieures.
  • enable_parallel_select_for_insert_select_into_part_table : active ou désactive la fonctionnalité qui vous permet d'insérer des données dans des tables partitionnées. Ce paramètre est désactivé par défaut dans PostgreSQL 16 et versions ultérieures.

Pour que le planificateur de requêtes puisse envisager un plan parallèle, l'instruction INSERT SELECT doit être compatible avec le parallélisme. Cela signifie qu'aucune partie de l'opération ne peut contenir de fonctions ou d'expressions qui ne peuvent pas être exécutées en parallèle de manière sécurisée. Si une partie de la requête est considérée comme non sécurisée pour le parallélisme, l'optimiseur revient à un plan non parallèle. Pour en savoir plus, consultez parallel-safety.

Conditions empêchant l'exécution parallèle

L'optimiseur de requête n'utilise pas de plan parallèle si l'instruction INSERT SELECT est considérée comme non sécurisée pour le parallélisme. Les conditions suivantes empêchent la parallélisation :

  • La table cible est une table étrangère.
  • La requête utilise une expression de table commune (CTE) modifiable qui contient une instruction de modification des données, par exemple DELETE.
  • Un index sur la table cible utilise une expression ou une fonction parallèle non sécurisée.
  • Une colonne de la table cible a une valeur par défaut qui utilise une fonction parallèle non sécurisée.
  • Un déclencheur sur la table cible utilise une expression ou une fonction parallèle non sécurisée.
  • La table cible comporte une colonne DOMAIN avec une contrainte CHECK qui utilise une fonction parallèle non sécurisée.
  • Une contrainte CHECK sur la table cible contient une expression ou une fonction parallèle non sécurisée.
  • La table cible est une table partitionnée et enable_parallel_select_for_insert_select_into_part_table est désactivé.

Avant de commencer

Ce document suppose que vous disposez d'une base de données AlloyDB. Pour créer une base de données, consultez Créer un cluster et son instance principale et Créer et gérer une base de données.

Rôles requis

Pour obtenir les autorisations nécessaires pour modifier les indicateurs de base de données au niveau de la session, demandez à votre administrateur de vous accorder le rôle IAM (Identity and Access Management) Utilisateur de base de données AlloyDB (roles/alloydb.databaseUser) sur votre projet. Pour en savoir plus sur l'attribution de rôles, consultez Gérer l'accès aux projets, aux dossiers et aux organisations.

Activer les paramètres d'exécution parallèle

Pour activer l'exécution parallèle pour les tables cibles partitionnées, procédez comme suit :

  1. Dans la console Google Cloud , accédez à la page Clusters.

    accéder aux clusters

  2. Sélectionnez un cluster dans la liste.

  3. Dans le menu de navigation, cliquez sur AlloyDB Studio.

  4. Connectez-vous à AlloyDB Studio à l'aide du nom de votre base de données, de votre nom d'utilisateur et de votre mot de passe.

  5. Définissez le GUC enable_parallel_select_for_insert_select_into_part_table sur on.

    SET enable_parallel_select_for_insert_select_into_part_table = on;
    

    Une fois le paramètre GUC activé, le planificateur de requêtes prend automatiquement en compte les plans parallèles pour les instructions INSERT INTO ... SELECT dont la cible est une table partitionnée, à condition que la requête soit considérée comme compatible avec le traitement parallèle.

    L'exemple suivant génère un plan EXPLAIN qui affiche un nœud Gather, ce qui indique que SELECT de source_table est exécuté en parallèle.

    -- Create a partitioned table
    CREATE TABLE part_table (a INT, b TEXT) PARTITION BY RANGE (a);
    CREATE TABLE part_table_1 PARTITION OF part_table FOR VALUES FROM (MINVALUE) TO (1000);
    CREATE TABLE part_table_2 PARTITION OF part_table FOR VALUES FROM (1000) TO (MAXVALUE);
    
    -- Create a source table
    CREATE TABLE source_table (c1 INT, c2 TEXT);
    INSERT INTO source_table SELECT i, 'value_' || i FROM generate_series(1, 2000) i;
    ANALYZE source_table;
    
    -- Enable the feature
    SET enable_parallel_select_for_insert_select_into_part_table = on;
    -- Optional for parallelizing the query with a small amount of data
    SET parallel_setup_cost=0;
    SET parallel_tuple_cost=0;
    SET min_parallel_table_scan_size=0;
    
    -- Run the insert with a parallelizable select
    EXPLAIN INSERT INTO part_table SELECT * FROM source_table;
    

    Cela renvoie le résultat suivant :

    EXPLAIN (COSTS OFF) INSERT INTO part_table SELECT * FROM source_table;
                    QUERY PLAN                   
    -----------------------------------------------
    Insert on part_table
    ->  Gather
            Workers Planned: 2
            ->  Parallel Seq Scan on source_table
    (4 rows)
    

Désactiver les paramètres d'exécution parallèle

Pour désactiver les paramètres :

  1. Dans la console Google Cloud , accédez à la page Clusters.

    accéder aux clusters

  2. Sélectionnez un cluster dans la liste.

  3. Dans le menu de navigation, cliquez sur AlloyDB Studio.

  4. Connectez-vous à AlloyDB Studio à l'aide du nom de votre base de données, de votre nom d'utilisateur et de votre mot de passe.

  5. Pour désactiver le paramètre enable_parallel_select_for_insert_select, exécutez la commande SQL suivante :

    SET enable_parallel_select_for_insert_select = OFF;
    
  6. Pour désactiver le paramètre enable_parallel_select_for_insert_select_into_part_table, exécutez la commande SQL suivante :

    SET enable_parallel_select_for_insert_select_into_part_table = OFF;
    

Vérifier un plan parallèle

Vous pouvez vérifier que l'optimiseur utilise un plan parallèle à l'aide de la commande EXPLAIN. Recherchez un nœud Gather et les attributs Workers Planned ou Workers Launched dans le plan de requête.

Exemple de tableau standard

Dans l'exemple de plan suivant, six processus de nœud de calcul sont lancés pour un hachage parallèle afin d'exécuter l'instruction SELECT.

EXPLAIN (ANALYZE)
INSERT INTO t1 SELECT t2.* FROM t1, t2 WHERE t1.c1 != t2.c1 AND t1.c2 = t2.c2;

                                 QUERY PLAN
------------------------------------------------------------------------------------
 Insert on t1  (cost=1209138.00..12801765.49 rows=0 width=0) (actual time=16812.677..19337.150 rows=0 loops=1)
   ->  Gather  (cost=1209138.00..12801765.49 rows=99995407 width=24) (actual time=16812.674..19337.144 rows=0 loops=1)
         Workers Planned: 6
         Workers Launched: 6
         ->  Parallel Hash Join  (...)
(...)

Exemple de table partitionnée

L'exemple suivant montre qu'après avoir activé la fonctionnalité pour les tables partitionnées, le plan affiche un nœud Gather avec quatre nœuds de calcul prévus pour SELECT.

-- First, enable the feature for partitioned tables
SET enable_parallel_select_for_insert_select_into_part_table = ON;

-- Then, explain the query
EXPLAIN (COSTS OFF) INSERT INTO part_table SELECT * FROM source_table;
                  QUERY PLAN                   
-----------------------------------------------
 Insert on part_table
   ->  Gather
         Workers Planned: 2
         ->  Parallel Seq Scan on source_table
(4 rows)

Étapes suivantes