INSERT SELECT-Leistung mit parallelem SELECT verbessern

Durch die parallele Ausführung des SELECT-Teils einer INSERT INTO ... SELECT-Abfrage kann die Abfrageleistung von AlloyDB for PostgreSQL verbessert werden, insbesondere bei partitionierten Tabellen und komplexen Abfragen.

Durch die Parallelisierung des SELECT-Unterplans verwendet die Datenbank mehrere Worker-Prozesse zum Abrufen von Daten. Die Datenbank fügt die abgerufenen Daten dann in die Zieltabelle ein. Diese Aufteilung der Aufgaben kann zu einer Verbesserung der Datenbankleistung führen.

Funktionsweise paralleler Abfragepläne in PostgreSQL

In PostgreSQL kann der Abfrageoptimierer einen parallelen Plan für eine gesamte Abfrage oder einen Teil einer Abfrage erstellen. Wenn ein paralleler Plan generiert wird, wird oben im Plan ein Gather- oder Gather Merge-Knoten hinzugefügt.

Dieser Knoten koordiniert mehrere parallele Workerprozesse. Jeder Worker führt einen Teil der Aufgabe aus, z. B. das Scannen eines Teils einer Tabelle. Der Gather-Knoten sammelt dann die Ergebnisse von allen Workern und übergibt sie an die nächste Phase der Abfrage oder zurück an den Client.

Im folgenden Abfrageplan ist beispielsweise ein Gather-Knoten zu sehen, der fünf Worker-Prozesse für einen parallelen sequenziellen Scan der Tabelle t1 verwenden möchte.

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)

Parallele Ausführung von INSERT...SELECT-Anweisungen

AlloyDB verbessert die Leistung von INSERT INTO ... SELECT, indem mehrere Worker-Prozesse verwendet werden, um die SELECT-Anweisung zu parallelisieren. Diese Aufteilung der Aufgaben kann zu einer Verbesserung der Datenbankleistung führen. Die Abfrage muss parallel sicher sein und es dürfen keine Bedingungen vorliegen, die eine Parallelisierung verhindern.

Bei vielen Datenbankvorgängen werden INSERT INTO ... SELECT-Anweisungen verwendet, um einer Tabelle neue Zeilen hinzuzufügen. Häufig ist der SELECT-Teil der Anweisung der ressourcenintensivste Teil der Abfrage.

Die Funktion wird durch die folgenden Konfigurationsparameter gesteuert:

  • enable_parallel_select_for_insert_select: Aktiviert oder deaktiviert die Funktion . Dieser Parameter ist in PostgreSQL 14 und höher standardmäßig aktiviert.
  • enable_parallel_select_for_insert_select_into_part_table: Aktiviert oder deaktiviert die Funktion, mit der Sie Daten in partitionierte Tabellen einfügen können. Dieser Parameter ist in PostgreSQL 16 und höher standardmäßig deaktiviert.

Damit der Abfrageplaner einen parallelen Plan in Betracht zieht, muss die INSERT SELECT-Anweisung parallel-safe sein. Das bedeutet, dass kein Teil des Vorgangs Funktionen oder Ausdrücke enthalten darf, die nicht sicher parallel ausgeführt werden können. Wenn ein Teil der Abfrage als nicht parallel sicher eingestuft wird, greift das Optimierungstool auf einen nicht parallelen Plan zurück. Weitere Informationen finden Sie unter parallel-safety.

Bedingungen, die eine parallele Ausführung verhindern

Die Abfrageoptimierung verwendet keinen parallelen Plan, wenn die INSERT SELECT-Anweisung als nicht parallel sicher gilt. Die folgenden Bedingungen verhindern die Parallelisierung:

  • Die Zieltabelle ist eine externe Tabelle.
  • Die Abfrage verwendet einen modifizierbaren CTE, der eine Datenänderungsanweisung enthält, z. B. DELETE.
  • Ein Index in der Zieltabelle verwendet einen parallelen unsicheren Ausdruck oder eine parallele unsichere Funktion.
  • Eine Spalte in der Zieltabelle hat einen Standardwert, für den eine parallel unsichere Funktion verwendet wird.
  • Ein Trigger für die Zieltabelle verwendet einen parallelen unsicheren Ausdruck oder eine parallele unsichere Funktion.
  • Die Zieltabelle hat eine DOMAIN-Spalte mit einer CHECK-Einschränkung, die eine parallel unsichere Funktion verwendet.
  • Eine CHECK-Einschränkung für die Zieltabelle enthält einen parallelen unsicheren Ausdruck oder eine parallele unsichere Funktion.
  • Die Zieltabelle ist eine partitionierte Tabelle und enable_parallel_select_for_insert_select_into_part_table ist deaktiviert.

Hinweise

In diesem Dokument wird davon ausgegangen, dass Sie eine AlloyDB-Datenbank haben. Informationen zum Erstellen einer Datenbank finden Sie unter Cluster und primäre Instanz erstellen und Datenbank erstellen und verwalten.

Erforderliche Rollen

Bitten Sie Ihren Administrator, Ihnen die IAM-Rolle „AlloyDB-Datenbanknutzer“ (roles/alloydb.databaseUser) für Ihr Projekt zuzuweisen, um die Berechtigungen zu erhalten, die Sie zum Ändern von Datenbankflags auf Sitzungsebene benötigen. Weitere Informationen zum Zuweisen von Rollen finden Sie unter Zugriff auf Projekte, Ordner und Organisationen verwalten.

Parameter für die parallele Ausführung aktivieren

So aktivieren Sie die parallele Ausführung für partitionierte Zieltabelle:

  1. Rufen Sie in der Google Cloud Console die Seite Cluster auf.

    Zu den Clustern

  2. Wählen Sie einen Cluster aus der Liste aus.

  3. Klicken Sie im Navigationsmenü auf AlloyDB Studio.

  4. Melden Sie sich mit dem Namen Ihrer Datenbank, Ihrem Nutzernamen und Ihrem Passwort in AlloyDB Studio an.

  5. Setzen Sie den enable_parallel_select_for_insert_select_into_part_table-GUC auf on.

    SET enable_parallel_select_for_insert_select_into_part_table = on;
    

    Nachdem Sie den GUC-Parameter aktiviert haben, berücksichtigt der Abfrageplaner automatisch parallele Pläne für INSERT INTO ... SELECT-Anweisungen, bei denen das Ziel eine partitionierte Tabelle ist, sofern die Abfrage als parallel sicher eingestuft wird.

    Das folgende Beispiel führt zu einem EXPLAIN-Plan mit einem Gather-Knoten, der angibt, dass die SELECT aus source_table parallel ausgeführt wird.

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

    Daraufhin wird die folgende Ausgabe zurückgegeben:

    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)
    

Parameter für die parallele Ausführung deaktivieren

So deaktivieren Sie die Parameter:

  1. Rufen Sie in der Google Cloud Console die Seite Cluster auf.

    Zu den Clustern

  2. Wählen Sie einen Cluster aus der Liste aus.

  3. Klicken Sie im Navigationsmenü auf AlloyDB Studio.

  4. Melden Sie sich mit dem Namen Ihrer Datenbank, Ihrem Nutzernamen und Ihrem Passwort in AlloyDB Studio an.

  5. Führen Sie den folgenden SQL-Befehl aus, um den Parameter enable_parallel_select_for_insert_select zu deaktivieren:

    SET enable_parallel_select_for_insert_select = OFF;
    
  6. Führen Sie den folgenden SQL-Befehl aus, um den Parameter enable_parallel_select_for_insert_select_into_part_table zu deaktivieren:

    SET enable_parallel_select_for_insert_select_into_part_table = OFF;
    

Parallelen Plan bestätigen

Mit dem Befehl EXPLAIN können Sie prüfen, ob der Optimierer einen parallelen Plan verwendet. Suchen Sie im Abfrageplan nach einem Gather-Knoten und den Attributen Workers Planned oder Workers Launched.

Beispiel für eine Standardtabelle

Im folgenden Planbeispiel werden sechs Workerprozesse für einen parallelen Hash-Join gestartet, um die SELECT-Anweisung auszuführen.

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  (...)
(...)

Beispiel für eine partitionierte Tabelle

Das folgende Beispiel zeigt, dass nach dem Aktivieren der Funktion für partitionierte Tabellen im Plan ein Gather-Knoten mit vier geplanten Workern für die SELECT angezeigt wird.

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

Nächste Schritte