update vieler Datensätze (z.b. 500) in einem Statement.

Themen rund um den praktischen Einsatz von Firebird. Fragen zu SQL, Performance, Datenbankstrukturen, etc.

Moderator: thorben.braun

Antworten
Hamburgo
Beiträge: 125
Registriert: Di 28. Mai 2019, 17:28

Hallo zusammen,

gibt es eine Möglichkeit ein Update vieler einzelner Datensätze (z.b. 500) in einem Statement
abzusetzen bzw. korrekter formuliert, mit einer Datenübertragung vom Client
an den Server zu senden ?

Insert's wären auch interessant.

Danke und viele Grüße
bfuerchau
Beiträge: 485
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Theoretisch ja, allerdings unterliegt man da gewissen Einschränkungen:
Es sind max. 255 Tabellen in einem Statement erlaubt.
Die Statementlänge beträgt bis 2.5 64KB, ab 3.0 ca. 10MB.
Du musst das Ganze in einen Execute Block verpacken, denn nur dann sind mehrere Statements erlaubt:

execute block
begin
insert ...;
insert ...;
update ....;
update or insert ....;
end

Allerdings wirst du dabei feststellen, dass dies so ggf. länger dauert, als einzelne Insert/Update.
Begründung:

Ein Insert per "insert into a (f1, f2) values(123, 'ABC')" dauert im Schnitt 5 - 10 mal länger als ein "insert into a (f1, f2) values(?, ?)".
Packt man mehrere Inserts der Variante 1 in einen Execute Block verlängert sich die Zeit sogar noch, da der Aufwand der Analyse ungleich größer ist als beim simplen Insert.

Die 2. Variante benutzt Parametermarker, braucht nur einmal analysiert zu werden und kann endlos oft sofort wieder verwendet werden.
Analyse des Statements ist bereits durchgeführt, der Typ des Wertes zum Parameter wird sofort als fehlerhaft erkannt wenn er nicht passend übergeben wird.
Bedennke nur, wieviele Vaianten es für Zahlen oder Datum gibt.
-> 123
-> 123.45
-> -12
-> -3E+12
-> '01.01.2022' (Euro)
-> '2022-01-01' (ISO)
-> '01/01/2022' (USA)
usw.
Dies benötigt halt Zeit, die bei der Übergabe eines Parameters schlichtweg entfällt. Einem numerischen oder Datumparameter kannst du nur einen passenden Wert übergeben.
Auch das O'Hara-Problem entfällt damit (Verdoppelung Hochkommata) sowie das Thema SQL-Injection.

Einschränkung 255 Tabellen:
Da nun jeder einzelne SQL als einzelner Tabellenzugriff gezählt wird, auch wenn er immer dieselbe Tabelle verwendet, kannst du halt nicht mehr als 255 SQL's in einem Block absetzen.

Einschränkung Blobs:
Da du ja ohne Parameter Textblobs in Hochkomma übergeben musst, ist die natürliche Länge auf 32K beschränkt. Dies ist die maximale Größe eines CHAR-Feldes, bei UTF8 sind das dann 8K.

Am meisten gewinnst du durch Parallelisierung in Threads:
Thread 1: Daten verarbeiten und Feldliste in eine Queue schreiben.
Thread 2: Queue lesen und an DB senden.
Alleine auf diesem Wege erreiche ich je nach Anzahl Spalten zwischen 2000 - 4000 Inserts/Sekunde mit Parametern.

Ich habe einen Bulkcopy für die FB in C# mit dem .Net-Treiber entwickelt der unter diesen Berücksichtigungen je nach Datensatzlänge (alle Felder einer Zeile) und der DB-Version (2.5, >= 3.0) das Maximum herausholt.
Auf diesem Wege erreiche ich im Schnitt das Doppelte im Maximum bei geringer Spaltenanzahl das 10-fache der o.a. Inserts.
Da ich BLOBs für meine Anwendung nicht benötge unterstütze ich diese auch nicht.
Hamburgo
Beiträge: 125
Registriert: Di 28. Mai 2019, 17:28

Herzlichen Dank für die detaillierte Antwort.

Nun sind wohl erstmal ein paar Test-Läufe mit Zeit-Messungen
angesagt, um herauszufinden ob es per "execute block"
in meinem Fall was bringt oder halt nicht.
bfuerchau
Beiträge: 485
Registriert: Mo 7. Mai 2018, 18:09
Kontaktdaten:

Achte halt darauf nur mit Parametermarkern zu arbeiten. Was anderes hat wirklich keinen Sinn.
Da für jeden Parametermarker "?" genau 1 Parameter zuständig ist und wenn du die Felder genau kennst, geht das eigentlich sehr schnell, um herauszufinden was das Maximum je Execute ist.
Nicht zu vergessen, dass die Sätze, die übrigbleiben, also keinen vollen Block ergeben, über einen neuen Block mit dem Rest oder dann einzeln zu übertragen sind.
Antworten