langsames Laden von Daten aus mysqldump

21

Ich habe eine mittelgroße MySQL-Datenbank mit etwa 30 Tabellen, von denen einige 10 Millionen Datensätze und einige 100 Millionen sind. Die mysqldumpvon allen Tabellen (in separate Dateien) ist ziemlich schnell, dauert vielleicht 20 Minuten. Es werden ca. 15 GB Daten generiert. Die größten ausgelagerten Dateien liegen im Bereich von 2 GB.

Wenn ich die Daten auf einer anderen Box, einer 8-GB-Maschine mit sechs Kernen, in MySQL lade, dauert es ewig. Leicht 12 Uhr Stunden oder mehr.

Ich lasse gerade den Mysql-Klienten laufen, um die Akte zu laden, dh

mysql database < footable.sql

direkt mit der datei direkt aus mysqldump heraus

mysqldump database foo > footable.sql

Offensichtlich mache ich etwas falsch. Wo fange ich an, damit es in einer angemessenen Zeit fertig wird?

Ich benutze keine Schalter auf dem Dump oder der Last.

Pat Farrell
quelle
Sie können die binäre Protokollierung auch während des
Ladens

Antworten:

22

Berücksichtigen Sie diese Punkte, die Ihnen bei der Erstellung und Wiederherstellung des Speicherauszugs helfen können.

  1. Verwenden Sie Extended insertsin Deponien.
  2. Dump mit --tabFormat, so dass Sie verwenden können mysqlimport, was schneller ist als mysql < dumpfile.
  3. Import mit mehreren Threads, einer für jede Tabelle.
  4. Verwenden Sie nach Möglichkeit ein anderes Datenbankmodul. das importieren in eine stark transaktionale engine wie innodb ist furchtbar langsam. Das Einfügen in eine nicht-transaktionale Engine wie MyISAM ist viel schneller.
  5. Deaktivieren Sie die Fremdschlüsselüberprüfung und aktivieren Sie die automatische Festschreibung.
  6. Wenn Sie nach innodb importieren, können Sie am effektivsten innodb_flush_log_at_trx_commit = 2Ihre my.cnf temporär in die Datei einfügen, während der Import ausgeführt wird. Sie können es wieder auf 1 setzen, wenn Sie SÄURE benötigen

Versuche es..

Abdul Manaf
quelle
Dein Tipp innodb_flush_log_at_trx_commit = 2hat mir den Tag gerettet. Das Importieren eines 600-MB-Dumps (als einzelne große Transaktion) hätte 6 Stunden gedauert, aber mit dieser vorübergehenden Einstellung war dies in 30 Minuten erledigt!
Daniel Marschall
1
Die Dinge, die Sie vor dem Versuch, eine 80gig-Datenbank aus einem Speicherauszug zu laden, 4 Tage nach dem Drücken der Eingabetaste wussten ... :)
Dmitri DB
7

Zusätzlich zu Abdul's Antwort möchte ich die Wichtigkeit der --disable-keysOption betonen , die die Schlüssel ausschaltet, bis alle Daten für eine Tabelle geladen sind. Diese Option ist im Rahmen des --optUmschalters aktiviert, der standardmäßig aktiviert ist, es jedoch für wichtig erachtet, darauf hinzuweisen.

Wenn Sie während der Einfügungen keine Schlüssel überspringen, erstellt jede eingefügte Zeile den Index neu. Ein extrem langsamer Prozess.

Derek Downey
quelle
ist --disable-keys Teil des mysqldump? oder das nachladen?
Pat Farrell
Es wird in die Dump-Datei aufgenommen
Derek Downey
--optist standardmäßig aktiviert
jberryman
1
This option is effective only for nonunique indexes of MyISAM tables. It has no effect for other tables
Ethan Allen
7

Ich habe in letzter Zeit viel damit zu tun. Sie können die Importleistung definitiv verbessern, indem Sie die Importe parallel ausführen. Der größte Teil der Verlangsamung basiert auf E / A, aber Sie können immer noch eine 40% ige Verbesserung erzielen, indem Sie Daten in Tabellen speichern und diese dann beispielsweise mit 4 gleichzeitig importieren.

Sie können dies mit xargs wie folgt tun:

ls *.sql -1c | xargs -P4 -I tbl_name sh -c "mysql --user=username --password database < tbl_name"

Wenn die Dateien komprimiert werden, bevor sie an mysql gesendet werden, wird dies hauptsächlich aufgrund der verringerten E / A-Leistung nicht verlangsamt. Meine Tabellen wurden auf etwa 10: 1 komprimiert, sodass viel Speicherplatz gespart wird.

Ich habe festgestellt, dass auf 4-Kern-Computern die Verwendung von 4 Prozessen optimal ist, obwohl dies nur unwesentlich besser ist als die Verwendung von 3. Wenn Sie über SSDs oder ein schnelles RAID verfügen, werden Sie wahrscheinlich besser skalieren.

Einige andere Dinge zu beachten. Wenn Sie 4k-Sektor-Laufwerke haben, stellen Sie sicher, dass Sie key_cache_block_size=4096und haben myisam_block_size=4K.

Wenn Sie MyISAM-Tabellen verwenden, setzen Sie die myisam_repair_threads = 2oder höher. Auf diese Weise können Ihre zusätzlichen Kerne beim Neuaufbau von Indizes helfen.

Stellen Sie sicher, dass Sie überhaupt nicht tauschen. Wenn ja, verkleinern Sie das innodb_buffer_pool_size.

Ich denke, ich habe durch diese Optionen auch einiges an Speedup mit innnodb bekommen:

innodb_flush_method= O_DIRECT (LINUX ONLY)
innodb_flush_log_at_commit = 0
innodb_doublewrite=0
innodb_support_xa=0
innodb_checksums=0

(Die letzten drei habe ich nicht ausgiebig getestet - ich glaube, ich habe sie als Vorschläge im Internet gefunden.) Beachten Sie, dass innodb_flush_log_at_commit=0dies zu einer Beschädigung von MySQL-Abstürzen oder einem Stromausfall führen kann.

greg
quelle
Greg, willkommen auf der Seite und danke für deine Antwort. Können Sie Quellen oder Gründe für Ihre Vorschläge zu *_block_sizeund myisam_repair_threadsangeben? Wir sind uns auch nicht sicher, ob wir Ihnen einen Rat geben sollten, um Variablen basierend auf 'Vorschlägen aus dem Internet' abzustimmen :)
Derek Downey
5

Wenn Sie in erster Linie MyISAM - Tabellen haben, sollten Sie die Erhöhung Bulk Insert - Puffer . Folgendes steht in der MySQL-Dokumentation zum Festlegen von bulk_insert_buffer_size :

MyISAM verwendet einen speziellen baumartigen Cache, um Masseneinfügungen für INSERT ... SELECT, INSERT ... VALUES (...), (...), ... und LOAD DATA INFILE zu beschleunigen, wenn Daten zu nonempty hinzugefügt werden Tabellen. Diese Variable begrenzt die Größe des Cache-Baums in Bytes pro Thread. Wenn Sie den Wert auf 0 setzen, wird diese Optimierung deaktiviert. Der Standardwert ist 8 MB.

Sie müssen zwei Dinge tun

1) Fügen Sie es zu /etc/my.cnf hinzu

[mysqld]
bulk_insert_buffer_size=512M

2) Stellen Sie den globalen Wert dafür ein

SET GLOBAL bulk_insert_buffer_size = 1024 * 1024 * 512;

Wenn Sie nicht berechtigt sind, bulk_insert_buffer_size global festzulegen, führen Sie dies aus

service mysql restart

Dies gilt natürlich nicht für InnoDB.

Aus einem anderen Blickwinkel, unabhängig davon, ob es sich bei den Tabellen um InnoDB oder MyISAM handelt, können zu viele Indizes vorhanden sein, wenn die Indizes größer als die Tabelle sind. Ich bin normalerweise der Meinung, dass das Neuladen eines MyISAM-MySQL-Speicherauszugs dreimal so lange dauern sollte, wie der MySQL-Speicherauszug benötigt. Ich bin auch der Meinung, dass das Neuladen eines InnoDB-mysqldump viermal so lange dauern sollte, wie der mysqldump benötigt.

Wenn Sie das Verhältnis 4: 1 zum erneuten Laden eines mysqldump überschreiten, haben Sie definitiv eines von zwei Problemen:

  • zu viele Indizes
  • Indizes sind aufgrund großer Spalten einfach zu groß

Sie können die Größe Ihrer Daten anhand der Speicher-Engine folgendermaßen messen:

SELECT IFNULL(B.engine,'Total') "Storage Engine",
CONCAT(LPAD(REPLACE(FORMAT(B.DSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Data Size", CONCAT(LPAD(REPLACE(
FORMAT(B.ISize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Index Size", CONCAT(LPAD(REPLACE(
FORMAT(B.TSize/POWER(1024,pw),3),',',''),17,' '),' ',
SUBSTR(' KMGTP',pw+1,1),'B') "Table Size" FROM
(SELECT engine,SUM(data_length) DSize,SUM(index_length) ISize,
SUM(data_length+index_length) TSize FROM
information_schema.tables WHERE table_schema NOT IN
('mysql','information_schema','performance_schema') AND
engine IS NOT NULL GROUP BY engine WITH ROLLUP) B,
(SELECT 3 pw) A ORDER BY TSize;

Überprüfen Sie, ob die Indizes mindestens so groß wie die Daten sind

Sie können die binäre Protokollierung auch wie folgt deaktivieren:

echo "SET SQL_LOG_BIN=0;" > footable.sql
mysqldump --databases foo >> footable.sql

bevor Sie das Skript neu laden

RolandoMySQLDBA
quelle
Ich weiß nicht, wie oft Sie meinen Tag gerettet haben, aber es war sicher eine Menge
Dmitri DB
2

Wenn Sie das Dateisystem komplett umgehen und nur die Ausgabe von mysqldump direkt in einen MySQL-Prozess leiten, sollten Sie merkliche Leistungsverbesserungen feststellen. Wie viel letztendlich von der Art des verwendeten Laufwerks abhängt, aber ich verwende selten mehr Speicherauszugsdateien, unabhängig von der Datenbankgröße, allein aus diesem Grund.

mysqldump -uxxx -pxxx -hxxx --single-transaction --routines --databases dbname | mysql -uyyy -pyyy -hyyy
Marcus Pope
quelle
1

Nach meinen Erfahrungen ist die Festplatte der Engpass. Vergiss rotierende Scheiben. SSD ist besser, aber bei weitem das Beste ist, dies im RAM durchzuführen - wenn Sie genug haben, um die gesamte Datenbank für eine kurze Zeit zu halten. Grob:

  1. Stoppen Sie mysqld
  2. Verschieben Sie vorhandene Inhalte von / var / lib / mysql
  3. Erstellen Sie ein leeres / var / lib / mysql-Verzeichnis
  4. mount -t tmpfs -o Größe = 32g tmpfs / var / lib / mysql (Größe anpassen)
  5. Erstelle eine leere Datenbank (zB mysql_install_db, oder stelle den vorherigen Inhalt wieder her)
  6. starte mysqld
  7. einführen
  8. Stoppen Sie mysqld
  9. Kopieren Sie / var / lib / mysql nach mysql2
  10. umount mysql; rmdir mysql
  11. Verschiebe mysql2 nach mysql
  12. Starte mysqld, sei glücklich

Für mich kann ein Speicherauszug von ~ 10G (/ var / lib / mysql, der ~ 20G verbraucht) in ungefähr 35 Minuten (mydumper / myloader), 45 Minuten (mysqldump --tab / mysqlimport), 50 Minuten (mysqldump / mysql) importiert werden. auf einem 2 x 6-Core-Xeon mit 3,2 GHz.

Wenn Sie nicht genug RAM auf einem einzelnen Computer haben, aber mehrere Computer mit schnellem Netzwerk nebeneinander haben, wäre es interessant zu sehen, ob ihre RAMs mit nbd (Network Block Device) verbunden werden können. Mit innodb_file_per_table können Sie den obigen Vorgang wahrscheinlich für jede Tabelle wiederholen.

egmont
quelle
Aus Neugier habe ich versucht, das mysql-datadir im RAM zu speichern, um es mit einer SSD (SSDSC2BB48 für Interessenten) für eine 2-GB-Datenbank zu vergleichen. Die Ergebnisse waren IDENTISCH, beide benötigten 207-209 Sekunden. In Anbetracht der Tatsache, dass Sie auch mysql starten / stoppen und die Verzeichnisse kopieren müssen, war die Verwendung einer RAM-Disk anstelle der SSD in meinem Fall viel langsamer
Shocker
Wenn Sie ca. 3-4 Minuten gebraucht haben, haben Sie vermutlich eine erheblich kleinere Datenbank als in diesem Thema beschrieben. Es wäre interessant zu erfahren, welche Erfahrungen Sie mit ähnlich großen Datenbanken gemacht haben wie in diesem Thema.
egmont