PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Verständnis von JDBC-Batch-Operationen

Es können verschiedene Arten von Batching beteiligt sein, und ich würde einen Teil davon des PostgreSQL-JDBC-Treibers (pgjdbc) behandeln.

TL;DR:pgjdbc verwendet weniger Netzwerk-Roundrips, falls die Batch-API verwendet wird. BatchedQuery wird nur verwendet, wenn reWriteBatchedInserts=true wird an die pgjdbc-Verbindungseinstellungen übergeben.

Möglicherweise finden Sie https://www.slideshare.net/VladimirSitnikv/postgresql-and-jdbc-striving-for-high-performance relevant (Folie 44,...)

Wenn es um die Ausführung von Abfragen geht, ist die Netzwerklatenz oft ein wesentlicher Teil der verstrichenen Zeit.

Angenommen, es sollen 10 Zeilen eingefügt werden.

  1. Kein Batching (z. B. nur PreparedStatement#execute in einer Schleife). Der Treiber würde Folgendes ausführen

    execute query
    sync <-- wait for the response from the DB
    execute query
    sync <-- wait for the response from the DB
    execute query
    sync <-- wait for the response from the DB
    ...
    

    Eine beträchtliche Zeit würde mit dem "Warten auf die DB"

    verbracht
  2. JDBC-Batch-API. Das ist PreparedStatement#addBatch() ermöglicht es dem Treiber, mehrere "Abfrageausführungen" in einem einzigen Netzwerk-Roundtrip zu senden. Die aktuelle Implementierung würde jedoch immer noch große Batches in kleinere aufteilen, um TCP-Deadlocks zu vermeiden.

    Die Aktionen wären viel besser:

    execute query
    ...
    execute query
    execute query
    execute query
    sync <-- wait for the response from the DB
    
  3. Beachten Sie, dass dies auch bei #addBatch der Fall ist , gibt es Overhead von Befehlen zum Ausführen von Abfragen. Der Server benötigt beträchtliche Zeit, um jede Nachricht einzeln zu verarbeiten.

    Eine der Möglichkeiten, die Anzahl der Abfragen zu reduzieren, ist die Verwendung von Inserts mit mehreren Werten. Zum Beispiel:

    insert into tab(a,b,c) values (?,?,?), (?,?,?), ..., (?,?,?)
    

    Dieses PostgreSQL ermöglicht das gleichzeitige Einfügen mehrerer Zeilen. Der Nachteil ist, dass Sie keine detaillierte Fehlermeldung (pro Zeile) haben. Derzeit implementiert Hibernate keine Mehrfachwert-Einfügung.

    Allerdings kann pgjdbc seit 9.4.1209 (2016-07-15) reguläre Batch-Einfügungen in Mehrfachwerte umschreiben.

    Um das Umschreiben mehrerer Werte zu aktivieren, müssen Sie reWriteBatchedInserts=true hinzufügen Verbindungseigenschaft. Die Funktion wurde ursprünglich in https://github.com/pgjdbc/pgjdbc/pull/491

    entwickelt

    Es ist schlau genug, 2 Anweisungen zu verwenden, um 10 Zeilen einzufügen. Die erste ist eine 8-wertige Aussage und die zweite eine 2-wertige Aussage. Die Verwendung von Zweierpotenzen ermöglicht es pgjdbc, die Anzahl unterschiedlicher Anweisungen vernünftig zu halten, und dies verbessert die Leistung, da häufig verwendete Anweisungen serverseitig vorbereitet werden (siehe Was ist die Lebensdauer einer serverseitig vorbereiteten PostgreSQL-Anweisung)

    BatchedQuery stellt diese Art von mehrwertigen Anweisungen dar, sodass Sie sehen, dass diese Klasse in reWriteBatchedInserts=true verwendet wird nur Fall.

    Die Nachteile des Features können sein:niedrigere Details als das "Batch-Ergebnis". Zum Beispiel gibt Ihnen der reguläre Stapel "pro Anweisung Zeilenanzahl", aber im Fall von mehreren Werten erhalten Sie nur den Status "Anweisung abgeschlossen". Darüber hinaus kann der On-the-Fly-Rewriter bestimmte SQL-Anweisungen möglicherweise nicht analysieren (z. B. https://github.com/pgjdbc/pgjdbc/issues/1045 ).