Migliorare il rendimento di INSERT SELECT con SELECT parallelo

L'utilizzo dell'esecuzione parallela per la parte SELECT di una query INSERT INTO ... SELECT può migliorare le prestazioni delle query AlloyDB per PostgreSQL, in particolare per le tabelle partizionate e le query complesse.

Parallelizzando il piano secondario SELECT, il database utilizza più processi worker per recuperare i dati. Il database inserisce quindi i dati recuperati nella tabella di destinazione. Questa divisione del lavoro può portare a miglioramenti delle prestazioni del database.

Come funzionano i piani di query parallele in PostgreSQL

In PostgreSQL, l'ottimizzatore di query può creare un piano parallelo per un'intera query o parte di una query. Quando viene generato un piano parallelo, viene aggiunto un nodo Gather o Gather Merge nella parte superiore del piano.

Questo nodo coordina più processi worker paralleli. Ogni worker esegue una parte dell'attività, ad esempio la scansione di una porzione di una tabella. Il nodo Gather raccoglie quindi i risultati di tutti i worker e li trasmette alla fase successiva della query o di nuovo al client.

Ad esempio, il seguente piano di query mostra un nodo Gather che prevede di utilizzare cinque processi di lavoro per una scansione sequenziale parallela nella tabella 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)

Esecuzione parallela per le istruzioni INSERT...SELECT

AlloyDB migliora le prestazioni di INSERT INTO ... SELECT utilizzando più processi di lavoro per parallelizzare l'istruzione SELECT. Questa divisione del lavoro può portare a miglioramenti delle prestazioni del database. La query deve essere sicura per l'esecuzione in parallelo e non devono essere presenti condizioni che impediscono la parallelizzazione.

Molte operazioni di database utilizzano istruzioni INSERT INTO ... SELECT per aggiungere nuove righe a una tabella. Spesso, la parte SELECT dell'istruzione è la parte della query che richiede più risorse.

La funzionalità è controllata dai seguenti parametri di configurazione:

  • enable_parallel_select_for_insert_select: attiva o disattiva la funzionalità . Questo parametro è attivo per impostazione predefinita in PostgreSQL 14 e versioni successive.
  • enable_parallel_select_for_insert_select_into_part_table: attiva o disattiva la funzionalità che consente di inserire dati nelle tabelle partizionate. Questo parametro è disattivato per impostazione predefinita in PostgreSQL 16 e versioni successive.

Affinché lo strumento di pianificazione delle query prenda in considerazione un piano parallelo, l'istruzione INSERT SELECT deve essere sicura per l'esecuzione parallela. Ciò significa che nessuna parte dell'operazione può contenere funzioni o espressioni che non possono essere eseguite in modo sicuro in parallelo. Se una parte della query viene considerata non sicura per l'esecuzione parallela, lo strumento di ottimizzazione torna a un piano non parallelo. Per ulteriori informazioni, consulta parallel-safety.

Condizioni che impediscono l'esecuzione parallela

L'ottimizzatore delle query non utilizza un piano parallelo se l'istruzione INSERT SELECT è considerata non sicura per l'esecuzione parallela. Le seguenti condizioni impediscono la parallelizzazione:

  • La tabella di destinazione è una tabella esterna.
  • La query utilizza un'espressione di tabella comune (CTE) modificabile che contiene un'istruzione di modifica dei dati, ad esempio DELETE.
  • Un indice nella tabella di destinazione utilizza un'espressione o una funzione non sicura per il parallelismo.
  • Una colonna della tabella di destinazione ha un valore predefinito che utilizza una funzione non sicura parallela.
  • Un trigger nella tabella di destinazione utilizza un'espressione o una funzione non sicura per il parallelismo.
  • La tabella di destinazione ha una colonna DOMAIN con un vincolo CHECK che utilizza una funzione parallela non sicura.
  • Un vincolo CHECK nella tabella di destinazione contiene un'espressione o una funzione non sicura per l'elaborazione parallela.
  • La tabella di destinazione è una tabella partizionata e enable_parallel_select_for_insert_select_into_part_table è disattivato.

Prima di iniziare

Questo documento presuppone che tu disponga di un database AlloyDB. Per creare un database, consulta Creare un cluster e la relativa istanza principale e Creare e gestire un database.

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per modificare i flag di database a livello di sessione, chiedi all'amministratore di concederti il ruolo IAM Utente database AlloyDB (roles/alloydb.databaseUser) sul tuo progetto. Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

Attiva i parametri di esecuzione parallela

Per attivare l'esecuzione parallela per le tabelle di destinazione partizionate:

  1. Nella console Google Cloud , vai alla pagina Cluster.

    Vai a Cluster

  2. Seleziona un cluster dall'elenco.

  3. Nel menu di navigazione, fai clic su AlloyDB Studio.

  4. Accedi ad AlloyDB Studio utilizzando il nome del database, il nome utente e la password.

  5. Imposta il GUC enable_parallel_select_for_insert_select_into_part_table su on.

    SET enable_parallel_select_for_insert_select_into_part_table = on;
    

    Dopo aver attivato il parametro GUC, il pianificatore di query prende automaticamente in considerazione i piani paralleli per le istruzioni INSERT INTO ... SELECT in cui la destinazione è una tabella partizionata, a condizione che la query sia considerata sicura per l'esecuzione parallela.

    Il seguente esempio genera un piano EXPLAIN che mostra un nodo Gather, il quale indica che l'SELECT di source_table viene eseguita in parallelo.

    -- 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;
    

    Viene restituito il seguente output:

    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)
    

Disattiva i parametri di esecuzione parallela

Per disattivare i parametri:

  1. Nella console Google Cloud , vai alla pagina Cluster.

    Vai a Cluster

  2. Seleziona un cluster dall'elenco.

  3. Nel menu di navigazione, fai clic su AlloyDB Studio.

  4. Accedi ad AlloyDB Studio utilizzando il nome del database, il nome utente e la password.

  5. Per disattivare il parametro enable_parallel_select_for_insert_select, esegui il seguente comando SQL:

    SET enable_parallel_select_for_insert_select = OFF;
    
  6. Per disattivare il parametro enable_parallel_select_for_insert_select_into_part_table, esegui il seguente comando SQL:

    SET enable_parallel_select_for_insert_select_into_part_table = OFF;
    

Verificare un piano parallelo

Puoi verificare che l'ottimizzatore stia utilizzando un piano parallelo utilizzando il comando EXPLAIN. Cerca un nodo Gather e gli attributi Workers Planned o Workers Launched nel piano di query.

Esempio di tabella standard

Nell'esempio di piano seguente, vengono avviati sei processi di lavoro per un hash join parallelo per eseguire l'istruzione 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  (...)
(...)

Esempio di tabella partizionata

L'esempio seguente mostra che, dopo aver attivato la funzionalità per le tabelle partizionate, il piano mostra un nodo Gather con quattro worker pianificati per 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)

Passaggi successivi