mysql insert - performance/robustheit, "best practice"

dermoritz

Bekanntes Mitglied
ich hab folgendes Problem: aus einer Textdatei(ca. 100MB!) sind Zeilenweise Einträge in eine DB(MySq) zu schreiben. Jede Zeile wird im Moment per RegExp geprüft. Aus einem bestimmten Teil einer Zeile (Zahlen Code) wird zudem ein Objekt erstellt - falls diese Erstellung gut geht ist der Code korrekt.
Mein Paln ist im Moment die Textdatei per "Scanner" einzulesen, das Objekt zu erstellen, dann daraus ein String der Form "(wert1,wert2,....)" zu machen und diesen einer Stringliste hinzuzufügen. Mit dieser Liste macht man dan eine "Insert into ... (spalte 1,spalte 2) values list[1],list[2]...." -Abfrage.

Wäre das schonmal ok soweit?

Nun wird diese Textdatei in regelmäßigen Abständen eingelesen und ab dem 2. einlesen werden ca. 99% der Einträge "MySQLIntegrityConstraintViolationException" werfen ( Duplicate entry '1846715-01-3' for key 1, der primary key ist zusammengesetzt). da frage ich mich ob ich diese abfangen soll oder ob es besser ist vorher per select statement eine "Blacklist" zu erstellen und dann das insert zu machen. Fall man solch ein "multi row insert" auf der mySql-Konsole macht bekommt man ja eine Zusammenfassung - wievile gesamt, wieviel eduplicate errors und wieviele warnings. Ich hätte gerne ein ähnliches Verhalten in Java. Bieten einem die Exception(s) sowas oder muss man selbst mitzählen?
 

dermoritz

Bekanntes Mitglied
Ich hab per Profiler mir die Performance mal angeschaut. Sehr viel Zeit eht bei mir durch die Instanziierung/Prüfung der Objecte drauf die dann in die DB rein sollen. Also hab ich mir gedacht, ich prüfe vor dieser Instanziierung ob das Objekt schon in der DB ist (anhand von 3 primary keys). Diese überprüfung (Select count(*) from tabelle where primK1=x and primK2=y and primK3=z) dauert aber in der Summe viel länger als das instanziieren der Objekte.
Also scheint es das schnellste zu sein bei jedem Mal alles erneut "zu-inserten" bzw. die verarbeiteten Zeilen zu löschen, zu markieren oder die gesamte Datei am Ende "wegzukopieren"?!
 
S

SlaterB

Gast
lade den alten DB-Inhalt bzw. die Index-Kombinationen in Java und dort in eine HashMap oder so,
in der Zeit eines DB-Zugriffs kannst du speicherintern tausend Dinge prüfen

und in MYSQL kann man glaube ich schneller Daten aus einer Textdatei importierten:
MySQL :: MySQL 5.1 Referenzhandbuch :: 3.3.3 Daten in Tabellen einladen

also:
im Programm prüfen was zu importieren ist, diese Befehle alle in eine Textdatei,
die am Ende einmal importieren
 

dermoritz

Bekanntes Mitglied
Danke für die Hinweise,

der 2. Tip kommt aber leider nicht in Frage, da die Daten aus der Textdatei nicht 1:1 in der DB landen. Vielmehr muss ich sie überprüfen(inkl Prüfsummenberechnung) und leicht umformatieren. Und dieser Prozess ist recht Zeitaufwendig. Der erst Import(DB noch leer) wird demnach lange dauern.
Was ich mich Frage ist was schneller/sicherer geht: Im Moment lade ich wie gesagt alle "Values" Klauseln(100000+ a 5 int-Werte) in ein riesiges String-Array (ist das Speichereffizient?) und baue (Stringbuilder) dann daraus eine entsprechend große Insert -Abfrage. Ist das prinzipiell OK? Gibt es eventuell etwas effizienteres als String-Array und StringBuilder? Oder sollte man prinzipiell in Blöcken arbeiten?

Das Problem mit dem wiederholten Insert schon vorhandener Einträge hab ich übrigens über umbenennung der Textdatei gelöst. Neu Einträge landen dann immer in einer neuen/leeren Textdatei und nur diese wird an das Programm verfüttert.
 
S

SlaterB

Gast
> der 2. Tip kommt aber leider nicht in Frage, da die Daten aus der Textdatei nicht 1:1 in der DB landen. Vielmehr muss ich sie überprüfen(inkl Prüfsummenberechnung) und leicht umformatieren.

nachdem du mit diesem Schritt fertig bist hast du x000 Datensätze im Java-Speicher,
diese kannst du nun direkt an die Datenbank schicken (einzeln sicher schlecht, zusammen vielleicht machbar, weiß nicht),
oder in eine neue Textdatei schreiben und dann diese von MySQL importieren lassen

-------

was du da mit String[] und tausenden Datensätzen macht kann wohl niemand aus den wenigen Sätzen beurteilen,
StringBuilder klingt aber gut,

kleine Performance-Test-Hilfe: kommentiere einzelne Programmteile aus, z.B. das Datei einlesen, das Formatieren, was immer das ist oder alles mit DB,
je nachdem wie lange der Rest dauert kann man ungefähr vermuten was ein Teil kostet,
wenn du alles ausklammerst nur nur noch das Einlesen und String[]/Builder-Aktionen drin hast und das recht schnell ist,
dann musst du über generelles String-Management nicht weiter nachdenken
 

dermoritz

Bekanntes Mitglied
Was mir im Moment sorgen macht ist der Speicherverbrauch. wenn die Textdatei 15-20mb groß ist, ist dann ein StringArray was das ganze mehr oder weiniger speichern soll ca. genauso groß? Das wäre ja kein Problem. Der Abfrag-Insert-String hätte dann nochmal dieselbe Größe - wäre auch noch kein Problem.

Es Zeile für Zeile nocheinmal in eine Textzeile schreiben wäre nur sinnvoll wenn ich mit dem Speicher nicht hinkäme?! Das würde dann alles sehr ewig dauern - alleine das Zählen der Zeilen einer Textdatei mit 150000 Zeilen dauert ewig (Programm läuft seid ca. 10min und ist noch nicht fertig, ich benutze wie gesagt die "Scanner"-Klasse)
 
S

SlaterB

Gast
deswegen einzelne Programmteile testen,
hier ein Testprogramm:
Java:
public class Test
{
    public static void main(String[] args)
        throws Exception
    {
        long time = System.currentTimeMillis();
        System.out.println("start");
        File f = new File("test.txt");
        BufferedWriter b = new BufferedWriter(new FileWriter(f));
        for (int i = 0; i < 160000; i++)
        {
            b.write("eine lange Zeile1");
            b.write("eine lange Zeile2");
            b.write("eine lange Zeile3");
            b.write("eine lange Zeile4");
            b.write("eine lange Zeile5");
            b.newLine();
        }
        b.close();
        System.out.println((System.currentTimeMillis() - time) + " file size: " + f.length());
        Scanner s = new Scanner(f);
        List<String> lines = new ArrayList<String>();
        while (s.hasNext())
        {
            lines.add(s.nextLine());
        }

        Runtime r = Runtime.getRuntime();
        long mem = r.totalMemory() - r.freeMemory();
        System.out.println((System.currentTimeMillis() - time) + " lines: " + lines.size() + ", mem: " + mem);
    }
}
Ausgabe:
Code:
start
219 file size: 13920000
2844 lines: 160000, mem: 36954632
das Programm erzeugt sich gar erst die Textdatei, 160.000 Zeilen, 14 MB,
danach alles eingelesen, 37 MB Speicherverbrauch (Faktor 2-5 Mehrverbrauch kann man ruhig annehmen)

alles zusammen unter 3 Sekunden

-------

> Es Zeile für Zeile nocheinmal in eine Textzeile schreiben wäre nur sinnvoll wenn ich mit dem Speicher nicht hinkäme?!

ich beziehe mich hauptsächlich auf die Dauer der Übertragung an die DB,
jedes Insert einzeln wäre ewig langsamer, aber vielleicht kann man auch aus Java tausende übergeben, 'Batch' und so,
genaues kann ich da nicht sagen

was ich weiß ist, wie oben zu sehen, dass man in wenigen Sekunden die halbe Festplatte an Text vollschreiben und auch lesen kann
 
Zuletzt bearbeitet von einem Moderator:

fastjack

Top Contributor
Hört sich nach einem normalen Datenimport an. Du bekommst eine Eingabedatei, baust daraus Objekte und fügst diese dann in eine Datenbank ein.

Da gibt es mehrere Möglichkeiten zur Steigerung der Performance, die auch ein wenig von den eigentlichen Daten abhängen :

* Eingabedatei besteht aus alten Daten (verändert oder gleichbleibend) und neuen :
Du könntest die Tabelle löschen und einfach alles wieder inserten. Bei MySql habe ich mit dieser Strategie gute Erfahrungen gemacht. --> keine Duplicate-Key Errors. Nicht empfehlenswert, wenn Du einige Millionen Zeilen einfügen willst :(
Oder Du verwendet die Syntax "insert into ... on duplicate key update ...". Hierbei wird bei einem doppelten Schlüssel geupdatet und Du erhälst keinen Fehler.

* Eingabedatei besteht nur aus neuen Daten :
Tja, der beste Fall. Einfach nur inserten ;)

* Allgemein :
In Paketen arbeiten. Das bedeutet z.B. 1000 Zeilen der Eingabedatei bearbeiten, 1000 Objekte erzeugen und einfügen/updaten. Speicher aufräumen (Listen/Objekte leeren/nullen, VM zur GC ankitzeln). Mit den nächsten 1000 weitermachen usw. 1000 Soll nur ein Beispiel sein, je nach Power kann man das natürlich varieren.
Wenn möglich, Transaktion(en) nutzen. Oder, wenn auf der Datentabelle/mit der Datenbank zusätzlich noch gearbeitet wird, Pausen einplanen. Ein paar Millisekunden reichen schon aus, um das Dauerfeuer auf die Datenbank zu unterbrechen/pausieren. Andere Nutzer werden dir es danken :)

Die Datenbanktabellen regelmäßig durch "optimize" optimieren, Indizes setzen etc.

Mit MySql (Diablo-Java, MyIsam /DB-Server: FreeBSD, DualCore ca. 2*3Ghz, 16GB) habe ich bis zu 50k-60k Inserts pro Minute durch Firmennetz erreicht.
 
Zuletzt bearbeitet:

dermoritz

Bekanntes Mitglied
danke für die tips!

in meinem fall (komplett neue daten) ist das Hauptproblem das erzeugen der Objekte. Da ihr sehr hohe Performance erreicht scheint da bei mir noch Optimierungspotential zu sein (bei mir brauchen 1000 inserts 2min). Das Problem ist das ich mir nicht sicher bin ob ich O(n) habe bei speicher und cpu :). Denn wenn irgendwann der Garbage -Collector beschäftig ist wird unberechenbar.
Lange Rede kurzer Sinn ich werde noch etwas Testen und eure Tips einfließen lassen und mich melden...
 

LCS

Mitglied
Hallo
Sorry wenn ich mich hier einfach so dranhänge, aber das Thema passt so gut, weil ich gerade auch so was mache. Ich hab in den letzen Jahren fast ausschließlich in Delphi/Pascal programmiert und schwenke jetzt gerade wieder auf Java um.
Wenn möglich, Transaktion(en) nutzen. Oder, wenn auf der Datentabelle/mit der Datenbank zusätzlich noch gearbeitet wird, Pausen einplanen. Ein paar Millisekunden reichen schon aus, um das Dauerfeuer auf die Datenbank zu unterbrechen/pausieren. Andere Nutzer werden dir es danken :)
Genau mein Problem. Könnte mir jemand ein paar Stichworte zur Transaktionssteuerung Java/MySQL geben? Ich brauch erst mal nen Ansatz zum experimentieren. Und ein kleiner Tipp zur Pause innerhalb der Verarbeitungsschleife wäre auch ganz nett.

Gruss
Lothar
 

dermoritz

Bekanntes Mitglied
Aus meiner wirklich bescheidenen Erfahrung würde ich sagen, falls die Datenbankanwendung komplexer wird und man Transaktionen braucht, sollte man eventuell JPA2.0 (Java Persistence Api) oder was ähnlcihes in Betracht ziehen. Bei mir ist es wirklich ganz ganz billig - eine Tabelle mit 5 oder 6 Werten.
 

fastjack

Top Contributor
Bei MySQL mußt Du die Tabellen mit dem Typen InnoDB anlegen, damit sie Transaktionen unterstützen. Standard ist MyISAM. Eine Pause in der Verarbeitungsschleife kannst Du z.B. mit

Java:
long millisekunden = 1000;
Thread.sleep(millisekunden);

machen.
 

LCS

Mitglied
Danke, das sleep hatte ich mittlerweile selbst gefunden :)

Die Tabellen in meiner Datenbank sind alles InnoDB Tabellen. Dass es im Connection Objekt commit() und rollback() gibt, hab ich inzwischen auch schon rausbekommen. Die Frage die bleibt ist, wie starte ich die Transaktion?

Gruss
Lothar
 
S

SlaterB

Gast
public void setAutoCommit(boolean autoCommit)
throws SQLException

Sets this connection's auto-commit mode to the given state. If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either the method commit or the method rollback. By default, new connections are in auto-commit mode.
Connection (Java 2 Platform SE v1.4.2)

kein Tutorial?..
 

LCS

Mitglied
Das war genau das, was noch gefehlt hat. Danke.

[OffTopic]
Tutorials bringen mich meist nicht so recht weiter. Meine Java Grundlagen liegen zwar schon 10 Jahre zurück, aber das kommt ganz gut wieder. Was ich bräuchte wäre eine Suchmaschine wo ich eine Delphi Klasse oder Methode eingebe und als Ergebnis kommt die Java Äquivalent raus. Wenn du sowas kennst.. :meld:
[/OffTopic]

Gruss
Lothar
 

fastjack

Top Contributor
Alternativ kannst Du die Transaktionssteuerung auch manuell mit den Methoden der Statement-Klasse als normale Queries absetzen :

begin - startet die Transaktion
commit - führt sie aus
rollback - setzt sie zurück

Es kann sein, das Du vorher das Auto-Commit abschalten mußt, das weis ich jetzt nicht so genau. Das geht dann über Connection.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
T MySQL MySQL - Insert into fügt zwei identische Datensätze ein Datenbankprogrammierung 2
P MySQL INSERT / UPDATE MySQL - perStoredProcedure oder direkt im Code Datenbankprogrammierung 3
R vor/nach INSERT mysql-SETS absetzen Datenbankprogrammierung 2
O Viele Verbindungen-Exception bei insert Daten zur MySQL-Datenbank Datenbankprogrammierung 2
B SELECT ja - INSERT nein (MySQL) Datenbankprogrammierung 3
F JAVA & MySQL : INSERT INTO DB ! Datenbankprogrammierung 2
E Fehler bei String-Insert in MySQL-DB Datenbankprogrammierung 8
S INSERT Befehl mit MySQL? Datenbankprogrammierung 7
C MySQL: INSERT INTO will nicht. Datenbankprogrammierung 7
R insert in MySQL - Fehlermeldung Datenbankprogrammierung 2
Juelin Java und MySQL MariaDB - WHERE-Klausel Datenbankprogrammierung 17
W MySQL-Connector funktioniert nicht über WLAN -> MacOS Datenbankprogrammierung 10
Juelin MySQL Datenbankmit glassfish und Netbeans Datenbankprogrammierung 18
Auf MySql Datenbank zugreifen funktioniert nicht Datenbankprogrammierung 8
TheSkyRider MySQL Datenbankzuordnung in Verbindung mit Java Datenbankprogrammierung 7
Warum funktioniert MySQL nicht Datenbankprogrammierung 8
M MySQL Datenbank in Array Datenbankprogrammierung 2
P MySQL- Neues Passwort Datenbankprogrammierung 1
btwX28 mysql abfrage über phpmyadmin Datenbankprogrammierung 8
sserio SQL oder MySQL Datenbankprogrammierung 44
OnDemand Mysql Query Builder Datenbankprogrammierung 1
Z MySQL "Too many connections" auch nach schliessen der Connections. Datenbankprogrammierung 10
yakazuqi MySQL MySQL Connection reset Datenbankprogrammierung 7
OnDemand MySql Foreign Key nötig oder unnötig Datenbankprogrammierung 3
M Mysql Views und Hibernate Caching Datenbankprogrammierung 4
W MYSQL Datenbank Login Android Datenbankprogrammierung 3
OnDemand MySQL und mongoDB wann macht was Sinn? Datenbankprogrammierung 11
bueseb84 Spring Boot : Update Mysql Datenbank Datenbankprogrammierung 1
Avalon Attribute werden mit Unterstrich in eine MySQL Datenbank eingetragen Datenbankprogrammierung 10
D MYSQL goorm IDE - Wie speichern? Datenbankprogrammierung 0
OnDemand Mysql UPDATE if condition Datenbankprogrammierung 14
D MySQL Geburtsdatum per KW abfragen Datenbankprogrammierung 1
C Java MySQL check if value exists in database Datenbankprogrammierung 2
H Fehler bei getConnection zu MySQL Datenbank Datenbankprogrammierung 18
J MySQL - Primary Key Date,Time vs ID Datenbankprogrammierung 16
ruutaiokwu MySQL: Messwerte, welche stagnieren interpolieren? Datenbankprogrammierung 2
S Datenbank MySQL und Java Datenbankprogrammierung 8
Thallius MySQL JDBC auf Linux Server zu mySQL DB auf anderem Linux Server wirft Access denied Datenbankprogrammierung 5
P Adressadministration mit Java und mySQL Datenbankprogrammierung 14
D MySQL Abfrage Datenbankprogrammierung 5
D MySQL Abfrage sortieren Datenbankprogrammierung 4
platofan23 MySQL Java Programm findet Treiber für mySQL auf Debian-Server nicht? Datenbankprogrammierung 11
J MySQL MySQL Risiken bei Stromausfall minimieren Datenbankprogrammierung 9
D MySQL Abfrage SUM datediff Datenbankprogrammierung 3
H MySQL MySQL - Keine Verbindung zur Datenbank?! Datenbankprogrammierung 4
G MySQL Problem mit MySQL verbindung Datenbankprogrammierung 8
X MySQL Java hat keinen Zugriff auf MySQL Datenbankprogrammierung 9
Z [JDBC][MYSQL] Access denied Datenbankprogrammierung 7
D MySQL Connection richtig herstellen. Wie ? Datenbankprogrammierung 7
D Multiple Connection mit MySQL Datenbankprogrammierung 4
D MySQL Eibinden des "mysql-connector" in eine fertige Jar Datenbankprogrammierung 3
L MySQL Android zu externer MySQL Datenbank verbinden Datenbankprogrammierung 5
P Daten in eine mySQL Datenbank einfügen Datenbankprogrammierung 4
D MySQL Zeilen kumulieren Datenbankprogrammierung 8
D MySQL Abfrage mit kumulierten Werten Datenbankprogrammierung 16
K Servlet-MySQL DB Datenbankprogrammierung 2
X MySQL Json String in MySQL einfügen. Datenbankprogrammierung 20
OnDemand Update auf Mysql läuft nicht durch Datenbankprogrammierung 30
K Java Object mit Hibernate in MySQL abspeichern Datenbankprogrammierung 1
D Datumsformat aus MySQL ändern Datenbankprogrammierung 15
G MySQL Java Problem: Nullpointer Exception obwohl Daten vorhanden sind? Datenbankprogrammierung 2
K MySQL LAN-MySQL Server mit XAMPP Datenbankprogrammierung 2
R ERModel der Datebanken (ORACLE,MySQL,MS-SQL usw) Datenbankprogrammierung 4
X MySQL In MySQL Funktionen erstellen, wenn Zelle leer dann andere Zelle ändern? Datenbankprogrammierung 9
K Anfängerfrage CSV in MySQL Datenbankprogrammierung 41
I MySQL Wert nachträglich bearbeiten Datenbankprogrammierung 1
N MySQL Datenbank lokal Datenbankprogrammierung 3
B MySQL: Port ändern über GUI? Wo und wie Port ändern? Datenbankprogrammierung 0
B MySQL installieren - silent / User anlegen Datenbankprogrammierung 3
X MySQL Verbindungdsaufbau MySql auf Ubuntu-Server Datenbankprogrammierung 10
F MySQL Wie kann ich in Java Datensätze aus einer MySQL Datenbank gezielt in einzelne Arrays schreiben? Datenbankprogrammierung 9
P MySQL JPA / MySQL - Fehler bei type=innoDB Datenbankprogrammierung 8
M MySQL MySQL DATETIME-Import Datenbankprogrammierung 9
P MySQL Connection Global Datenbankprogrammierung 13
J mySQL- Java Application - Zugriff über Internet Datenbankprogrammierung 3
P MySQL-Verbindung in anderer Klasse nutzen Datenbankprogrammierung 2
D JavaFX Anwendung zugriff auf MySQL DB. Datenbankprogrammierung 2
D MySQL Grundsätzliche Fragen zu MySQL Datenbankprogrammierung 3
B MySQL LogIn Daten im Code verstecken Datenbankprogrammierung 3
M MySQL-Syntax-Fehler Datenbankprogrammierung 1
M In MySql Datenbank schreiben Datenbankprogrammierung 6
D mySQL Timestamp in RegularTimePeriod bzw Second Datenbankprogrammierung 3
H SHOW Tables in Java/MySQL Datenbankprogrammierung 8
windl MySQL und HSQLDB Datenbankprogrammierung 4
S Anbindung zur mysql von mit Swing und AWT Datenbankprogrammierung 22
F MySQL+ Netbeans: Datenbanken mit Automatisch generierten Entity Classes get und set Datenbankprogrammierung 2
I MySQL Hibernate / MySQL alias in WHERE clause Datenbankprogrammierung 1
C MYSQL kann wert nicht eintragen Datenbankprogrammierung 3
D Aktualisierung einer ListView mit Daten aus MySQL-DB Datenbankprogrammierung 5
F BPlaced MySql Datenbank ansprechen Datenbankprogrammierung 5
S MySQL MySQL will einfach nicht, bitte um Rat Datenbankprogrammierung 4
M MySQL Datenbank durchsuchen Datenbankprogrammierung 5
Z MySQL mysql Facharbeit: Tipps und Ideen gesucht Datenbankprogrammierung 5
dat_vin JavaFX Datenbankverbindung über JPA und MySQL Error Datenbankprogrammierung 0
K MySQL Datenbank 2facher Zugriff Datenbankprogrammierung 1
Z MySQL Shopsystem mit mysql und Java Datenbankprogrammierung 8
S [MySQL] Topliste Datenbankprogrammierung 2
H Datenbank-Anbindung Java/MySQL Datenbankprogrammierung 2
A Eine MySQL Zeile mit JDBC löschen Datenbankprogrammierung 5
J Dateien in MySQL speichern & indizieren Datenbankprogrammierung 2

Ähnliche Java Themen

Neue Themen


Oben