enhancement
major
defect
major
minor
major
#29773
PostgreSQL: Große SQL-Migrationen werden durch nicht freigegebene Autosave-Savepoints quadratisch langsam
Problem
Die Migration Ticket_28604_Upgrade_commit_messages(tl) (string-column-transform auf REVISION.log) hat auf einer PostgreSQL-Datenbank mit 2.849.412 Revisionen gut 12 Stunden gedauert:
- Umschreiben der Zeilen: 2026-10-06 20:00:30 bis 2026-10-07 04:04:35 (ca. 8 h)
- abschließender connection.commit() in DataMigration.executeSQLMigration(): 04:04:35 bis 08:11:14 (ca. 4 h)
Die Zeit pro Zeile stieg dabei linear mit der Anzahl bereits geänderter Zeilen in der Transaktion, die Gesamtlaufzeit also quadratisch:
| = geänderte Zeilen = | = ms/Zeile = |
| 16.000 | 0,44 |
| 466.000 | 1,9 |
| 1.048.000 | 6,6 |
| 2.027.000 | 15,8 |
| 2.828.000 | 20,8 |
Ursache
TopLogic verbindet sich per Default mit autosave=ALWAYS (%POSTGRESQL_AUTOSAVE% in db-postgresql.xml). Der Treiber setzt dann vor jedem Statement ein SAVEPOINT PGJDBC_AUTOSAVE. Ohne cleanupSavepoints=true (Treiber-Default: false) wird dieser Savepoint nie freigegeben. PostgreSQL behält gleichnamige ältere Savepoints, sodass jedes Statement eine weitere Ebene verschachtelter Subtransaktionen erzeugt.
StringReplacementProcessor ändert jede Zeile mit einem eigenen ResultSet.updateRow(), also einem eigenen UPDATE-Statement. In einer einzigen Migrationstransaktion entstehen so Millionen verschachtelter Subtransaktionen. Jede Zeile wird dadurch teurer, und der Commit muss alle Ebenen einzeln auflösen.
Lösung
Die Treiberoption cleanupSavepoints wird in db-postgresql.config.xml gesetzt, konfigurierbar über die neue Variable %POSTGRESQL_CLEANUP_SAVEPOINTS% (Umgebungsvariable postgresql_cleanup_savepoints, Default true):
{{{#!xml <option name="autosave" value="%POSTGRESQL_AUTOSAVE%" /> <option name="cleanupSavepoints" value="%POSTGRESQL_CLEANUP_SAVEPOINTS%" /> }}}
Der Treiber gibt den Autosave-Savepoint dann nach jedem erfolgreichen Statement wieder frei. Das Rollback-Verhalten von autosave=ALWAYS bleibt erhalten: Ein fehlgeschlagenes Statement wird weiterhin einzeln zurückgenommen, die Transaktion bleibt benutzbar.
Testläufe derselben Migration auf einem Datenstand mit ca. 2 Mio. Revisionen:
- autosave=ALWAYS mit cleanupSavepoints=true (Option fest eingetragen): ca. 5 Minuten
- zum Vergleich autosave=NEVER (keine Savepoints): ca. 5 Minuten
- vorher (autosave=ALWAYS ohne cleanupSavepoints): nach obigem Verlauf hochgerechnet mehrere Stunden
Bestehende Anwendungen können die Option bis zum Update bereits jetzt in ihrer eigenen Datenbankkonfiguration als <option name="cleanupSavepoints" value="true" /> ergänzen.