it-swarm.com.de

Mit mysqldump eine Einfügung pro Zeile formatieren?

Dies wurde einige Male gefragt, aber ich kann keine Lösung für mein Problem finden. Bei der Verwendung von mysqldump, dem integrierten Werkzeug für das MySQL Workbench-Verwaltungstool, erhalte ich beim Ablegen einer Datenbank mit erweiterten Inserts gewaltige lange Datenzeilen. Ich verstehe, warum dies so ist, da es die Einfügungen beschleunigt, indem die Daten als ein Befehl eingefügt werden (insbesondere bei InnoDB). Die Formatierung macht es jedoch WIRKLICH schwierig, die Daten in einer Dump-Datei zu betrachten oder zwei Dateien mit einem Vergleichstool zu vergleichen wenn Sie sie in der Versionskontrolle usw. speichern. In meinem Fall speichere ich sie in der Versionskontrolle, da wir die Dump-Dateien verwenden, um den Überblick über unsere Integrationstestdatenbank zu behalten.

Jetzt weiß ich, dass ich erweiterte Einfügungen deaktivieren kann. Daher bekomme ich pro Zeile eine Einfügung. Diese Funktion funktioniert, aber jedes Mal, wenn Sie die Dump-Datei wiederherstellen, wird sie langsamer.

Mein Kernproblem ist, dass das OLD-Tool (MySQL Administrator), das wir beim Ablegen einer Datei verwendet haben, im Grunde das Gleiche tut, jedoch FORMATS die INSERT-Anweisung, um eine Einfügung pro Zeile einzufügen, während gleichzeitig Masseneinfügungen ausgeführt werden. Also stattdessen:

INSERT INTO `coupon_gv_customer` (`customer_id`,`amount`) VALUES (887,'0.0000'),191607,'1.0300');

du bekommst das:

INSERT INTO `coupon_gv_customer` (`customer_id`,`amount`) VALUES 
 (887,'0.0000'),
 (191607,'1.0300');

Egal welche Optionen ich versuche, es scheint keine Möglichkeit zu geben, eine Mülldeponie wie diese zu bekommen, was wirklich das Beste aus beiden Welten ist. Ja, es braucht etwas mehr Platz, aber in Situationen, in denen Sie einen Menschen zum Lesen der Dateien benötigen, ist es VIEL nützlicher.

Fehlt mir etwas und es gibt eine Möglichkeit, dies mit MySQLDump zu tun, oder sind wir alle rückwärts gegangen und diese Funktion in dem alten (jetzt veralteten) MySQL-Administrator-Tool ist nicht mehr verfügbar?

40
Kendall Bennett

Bei dem standardmäßigen mysqldump-Format generiert jeder Datensatz einen einzelnen INSERT-Befehl in der dump-Datei (d. H. Die sql-Datei), jeder in seiner eigenen Zeile. Dies ist perfekt für die Quellensteuerung (z. B. SVN, GIT usw.), da die Differenz- und Delta-Auflösung viel feiner werden und letztendlich ein effizienterer Quellensteuerungsprozess erzielt wird. Die Ausführung all dieser INSERT-Abfragen kann jedoch bei Tabellen mit beträchtlicher Größe die Wiederherstellung aus der SQL-Datei möglicherweise zu langsam machen.

Mit der Option --extended-insert wird das mehrfache INSERT-Problem behoben, indem alle Datensätze in einem einzigen INSERT-Befehl in einer einzigen Zeile der abgelegten SQL-Datei zusammengefasst werden. Der Source-Control-Prozess wird jedoch sehr ineffizient. Der gesamte Tabelleninhalt wird in einer einzigen Zeile in der SQL-Datei dargestellt. Wenn sich ein einzelnes Zeichen irgendwo in dieser Tabelle ändert, kennzeichnet die Quellcodeverwaltung die gesamte Zeile (d. H. Die gesamte Tabelle) als Delta zwischen den Versionen. Bei großen Tabellen werden dadurch viele Vorteile des Einsatzes eines formalen Quellcodeverwaltungssystems zunichte gemacht.

Idealerweise möchten wir für eine effiziente Datenbankwiederherstellung in der SQL-Datei jede Tabelle durch eine einzelne INSERT-Datei darstellen. Für einen effizienten Quellcodeverwaltungsprozess möchten wir in der SQL-Datei, dass sich jeder Datensatz in diesem INSERT-Befehl in einer eigenen Zeile befindet.

Meine Lösung hierfür ist das folgende Backup-Skript:

#!/bin/bash

cd my_git_directory/

ARGS="--Host=myhostname --user=myusername --password=mypassword --opt --skip-dump-date"
/usr/bin/mysqldump $ARGS --database mydatabase | sed 's$VALUES ($VALUES\n($g' | sed 's$),($),\n($g' > mydatabase.sql

git fetch Origin master
git merge Origin/master
git add mydatabase.sql
git commit -m "Daily backup."
git Push Origin master

Das Ergebnis ist ein SQL-Datei-INSERT-Befehlsformat, das folgendermaßen aussieht:

INSERT INTO `mytable` VALUES
(r1c1value, r1c2value, r1c3value),
(r2c1value, r2c2value, r2c3value),
(r3c1value, r3c2value, r3c3value);

Einige Notizen:

  • passwort auf der Kommandozeile ... Ich weiß, nicht sicher, andere Diskussion.
  • --opt: Aktiviert unter anderem die Option --extended-insert (d. h. eine INSERT pro Tabelle).
  • --skip-dump-date: mysqldump fügt bei der Erstellung normalerweise einen Datums-/Zeitstempel in die SQL-Datei ein. Dies kann in der Quellcodeverwaltung störend sein, wenn das einzige Delta zwischen den Versionen der Datums-/Zeitstempel ist. Das Betriebssystem und das Quellcodeverwaltungssystem werden Datum und Uhrzeit der Datei und der Version stempeln. Es ist nicht wirklich in der SQL-Datei benötigt.
  • Die git-Befehle sind nicht zentral für die grundlegende Frage (Formatieren der SQL-Datei), sondern zeigen, wie ich meine SQL-Datei wieder in die Quellcodeverwaltung bekomme. Ähnliches kann mit svn gemacht werden. Wenn Sie dieses SQL-Dateiformat mit Ihrer Quellcodeverwaltung kombinieren, werden Sie feststellen, dass Ihre Benutzer beim Aktualisieren ihrer Arbeitskopien nur die Deltas (dh geänderte Datensätze) über das Internet verschieben müssen und die verschiedenen Dienstprogramme nutzen können um zu sehen, welche Datensätze in der Datenbank geändert wurden.
  • Wenn Sie eine Datenbank sichern, die sich auf einem Remote-Server befindet, führen Sie dieses Skript nach Möglichkeit auf diesem Server aus, um zu vermeiden, dass der gesamte Inhalt der Datenbank mit jedem Speicherauszug über das Netzwerk verschoben wird.
  • Richten Sie nach Möglichkeit ein Repository für die Quellcodeverwaltung für Ihre SQL-Dateien auf demselben Server ein, von dem aus Sie dieses Skript ausführen. checke sie von dort in das Repository. Dies hilft auch zu verhindern, dass bei jedem Speicherauszug die gesamte Datenbank über das Netzwerk gepusht werden muss. 
27
Todd Blumer

Verwenden Sie die folgende Option: --skip-extended-insert

Es hat für mich funktioniert.

31
Eric Tan

Wie andere bereits sagten, verwenden Sie sed zum Ersetzen von "), (" ist nicht sicher, da dies als Inhalt in der Datenbank erscheinen kann.). Dies kann jedoch folgendermaßen geschehen: folgende:

$ mysqldump -u my_db_user -p -h 127.0.0.1 --skip-extended-insert my_database > my_database.sql
$ sed ':a;N;$!ba;s/)\;\nINSERT INTO `[A-Za-z0-9$_]*` VALUES /),\n/g' my_database.sql > my_database2.sql

sie können auch "sed -i" verwenden, um die In-Line zu ersetzen.

Folgendes tut dieser Code:

  1. --skip-extended-insert erstellt für jede Zeile, die Sie haben, ein INSERT INTO.
  2. Jetzt verwenden wir sed, um die Daten zu bereinigen. Beachten Sie, dass das reguläre Suchen/Ersetzen mit sed für eine Zeile gilt, sodass das Zeichen "\ n" nicht erkannt werden kann, da sed Zeile für Zeile arbeitet. Deshalb setzen wir ": a; N; $! Ba;" was im Grunde sed anweist, mehrzeilig zu suchen und die nächste Zeile zu puffern.

Hoffe das hilft

10
Ace.Di

Wie wäre es, wenn Sie den Speicherauszug in einer CSV-Datei mit mysqldump speichern, indem Sie die --tab-Option wie folgt verwenden?

mysqldump --tab=/path/to/serverlocaldir --single-transaction <database> table_a

Dies erzeugt zwei Dateien:

  • table_a.sql, der nur die Anweisung zum Erstellen der Tabelle enthält; und
  • table_a.txt, der durch Tabulatoren getrennte Daten enthält.

WIEDERHERSTELLUNG

Sie können Ihre Tabelle über LOAD DATA wiederherstellen:

LOAD DATA INFILE '/path/to/serverlocaldir/table_a.txt' 
  INTO TABLE table_a FIELDS TERMINATED BY '\t' ...

LOAD DATA ist normalerweise 20 Mal schneller als mit INSERT-Anweisungen.

Wenn Sie Ihre Daten in einer anderen Tabelle wiederherstellen müssen (z. B. zu Überprüfungs- oder Testzwecken), können Sie eine "Spiegeltabelle" erstellen:

CREATE TABLE table_for_test LIKE table_a;

Laden Sie dann die CSV in die neue Tabelle:

LOAD DATA INFILE '/path/to/serverlocaldir/table_a.txt' 
  INTO TABLE table_for_test FIELDS TERMINATED BY '\t' ...

VERGLEICHEN SIE

Eine CSV-Datei ist am einfachsten für Vergleiche oder für den Blick in die Umgebung oder für technische Benutzer ohne SQL, die gängige Tools wie Excel, Access oder Befehlszeile verwenden (diff, comm usw.)

7
Cristian Porta

Ich fürchte, das wird nicht möglich sein. Im alten MySQL-Administrator habe ich den Code zum Ablegen von db-Objekten geschrieben, der völlig unabhängig von dem mysqldump-Tool war und daher eine Reihe zusätzlicher Optionen (wie diese Formatierung oder Fortschrittsrückmeldung) bot. In MySQL Workbench wurde beschlossen, stattdessen das Tool mysqldump zu verwenden, das neben dem Zurücksetzen in einigen Punkten und dem Erzeugen von Versionsproblemen den Vorteil hat, immer auf dem neuesten Stand zu bleiben.

Die kurze Antwort lautet also: Mit mysqldump ist derzeit keine Formatierung möglich.

5
Mike Lischke

Ich fand dieses Tool sehr hilfreich für den Umgang mit erweiterten Einfügungen: http://blog.lavoie.sl/2014/06/split-mysqldump-extended-inserts.html

Es analysiert die mysqldump-Ausgabe und fügt nach jedem Datensatz Zeilenumbrüche ein, verwendet jedoch immer die schnelleren erweiterten Einfügungen. Im Gegensatz zu einem sed-Skript sollte die Gefahr bestehen, dass Zeilen an der falschen Stelle gebrochen werden, wenn der Regex innerhalb einer Zeichenfolge übereinstimmt.

1
seanf

Versuche dies:

mysqldump -c -t --add-drop-table=FALSE --skip-extended-insert -uroot -p<Password> databaseName tableName >c:\path\nameDumpFile.sql
0

Ich mochte die Lösung von Ace.Di mit sed, bis ich diese Fehlermeldung erhielt: Sed: Speicher konnte nicht erneut zugewiesen werden

Also musste ich ein kleines PHP Skript schreiben

mysqldump -u my_db_user -p -h 127.0.0.1 --skip-extended-insert my_database | php mysqlconcatinserts.php > db.sql

Das Skript PHP generiert auch für 10.000 Zeilen ein neues INSERT, um Speicherprobleme zu vermeiden.

mysqlconcatinserts.php:

#!/usr/bin/php
<?php
/* assuming a mysqldump using --skip-extended-insert */
$last = '';
$count = 0;
$maxinserts = 10000;
while($l = fgets(STDIN)){
  if ( preg_match('/^(INSERT INTO .* VALUES) (.*);/',$l,$s) )
  {
    if ( $last != $s[1] || $count > $maxinserts )
    {
      if ( $count > $maxinserts ) // Limit the inserts
        echo ";\n";
      echo "$s[1] ";
      $comma = ''; 
      $last = $s[1];
      $count = 0;
    }
    echo "$comma$s[2]";
    $comma = ",\n";
  } elseif ( $last != '' ) {
    $last = '';
    echo ";\n";
  }
  $count++;
} 
0
Kjeld Flarup