MySQL LOAD DATA INFILE verlangsamt sich nach einigen Eingaben mit der InnoDB-Engine um 80%

14

Ich lade eine 100-GB-Datei über LOAD DATA INFILE. Ich hatte gute Erfolge mit MyISAM, ein paar Stunden und fertig.

Ich versuche es jetzt mit InnoDB. Der Ladevorgang beginnt schnell bei über 10 MB / Sek.file_per_table ).

Aber nach ungefähr 5 GB Daten verlangsamt es sich auf den Bereich von 2 bis 4 MB / s, da ich über 20 GB habe, war es um 2 MB / s niedriger.

Die Größe der InnoDB-Pufferpools beträgt 8 GB. Vor dem Ausführen des Befehls LOAD DATA INFILE habe ich Folgendes ausgeführt:

SET @@session.sql_log_bin=0;
SET autocommit=0;
SET unique_checks=0;
SET foreign_key_checks=0;
alter table item_load disable keys;
//Run LOAD DATA INFILE....

Ich kann den Grund nicht erkennen, warum es gut anfängt und sich mit der Zeit verlangsamt.

Außerdem habe ich mit denselben Einstellungen denselben Befehl LOAD DATA INFILE mit der Tabelle ausgeführt, wobei InnoDB und MyISAM sowie ein 5-GB-Testdatensatz verwendet wurden. MyISAM war 20-mal schneller:

InnoDB:

mysql> LOAD DATA CONCURRENT LOCAL INFILE '/tmp/item' REPLACE INTO TABLE item_load;
Query OK, 2630886 rows affected, 6 warnings (21 min 25.38 sec)
Records: 2630886  Deleted: 0  Skipped: 0  Warnings: 6

MyISAM:

mysql> LOAD DATA CONCURRENT LOCAL INFILE '/tmp/item' REPLACE INTO TABLE item_load;
Query OK, 2630886 rows affected, 6 warnings (1 min 2.52 sec)
Records: 2630886  Deleted: 0  Skipped: 0  Warnings: 6

Was sollte ich sonst noch versuchen? Die MyISAM-Engine kann die Laderate viel besser halten.


Zusätzliche Details:

  • Ich habe versucht, die Dateien einzeln zu laden, kein Unterschied.

  • Ich habe übrigens 150 Dateien mit je 500 MB, in jeder Datei sind die Schlüssel sortiert.

  • Nach dem Erreichen von 40 GB über Nacht, 12 Stunden später, war die Laderate auf 0,5 MB / s gesunken, was bedeutet, dass der Betrieb praktisch unmöglich ist.

  • Ich habe keine anderen Antworten auf ähnliche Fragen in anderen Foren gefunden. Es scheint mir, dass InnoDB das Laden großer Datenmengen in Tabellen mit einer Größe von mehr als einigen GB nicht unterstützt.

David Parks
quelle

Antworten:

7

BEOBACHTUNG # 1

Mir ist aufgefallen, dass du ausgeschaltet bist autocommit. Das wird so viele Daten in ibdata1 stapeln. Warum?

Es gibt sieben (7) Informationsklassen, die in ibdata1 gespeichert sind:

  • Datenseiten für InnoDB-Tabellen
  • Indexseiten für InnoDB-Tabellen
  • Datenwörterbuch
  • Doppelter Schreibpuffer
    • Sicherheitsnetz zur Verhinderung von Datenkorruption
    • Hilft beim Umgehen des Betriebssystems für das Caching
  • Puffer einfügen (Optimiert Änderungen an Sekundärindizes)
  • Rollback-Segmente
  • Protokolle rückgängig machen
  • Klicken Sie hier, um eine bildliche Darstellung von zu sehen ibdata1

Einige dieser Informationen werden abhängig von der Isolationsstufe für bestimmte Transaktionen sichtbar gemacht. Solche Aktionen können zu unbeabsichtigten Primärschlüsselsperren und vielen Phantomdaten führen . Wenn diese beiden Dinge zunehmen, sollten Sie mit einer deutlichen Verlangsamung rechnen.

Empfehlung: Autocommit eingeschaltet lassen

BEOBACHTUNG # 2

Ich sehe, du hast folgendes:

alter table item_load disable keys;

DISABLE KEYS funktioniert nicht mit InnoDB . Hier ist warum:

  • MyISAM: DISABLE KEYSBeendet einfach die Aktualisierung des Sekundärindex für die MyISAM-Tabelle. Wenn Sie INSERT in eine MyISAM-Tabelle mit deaktivierten Schlüsseln massen, wird die Tabelle schnell geladen, und der PRIMARY KEY und alle eindeutigen Indizes werden erstellt. Wenn Sie ausführen ENABLE KEYS, werden alle Sekundärindizes linear in der Tabelle erstellt und an die Tabelle angehängt.MYD .
  • InnoDB: Wie in der internen Abbildung von InnoDB gezeigt, hat der System-Tablespave ibdata1eine Struktur , die für das Einfügen von Sekundärindizes vorgesehen ist. Gegenwärtig gibt es keine Bestimmung, um Indizes wie MyISAM zu behandeln.

Beachten Sie zur Veranschaulichung meinen Versuch, DISABLE KEYS für eine InnoDB-Tabelle in MySQL auszuführen

mysql> show create table webform\G
*************************** 1. row ***************************
       Table: webform
Create Table: CREATE TABLE `webform` (
  `nid` int(10) unsigned NOT NULL,
  `confirmation` text NOT NULL,
  `confirmation_format` tinyint(4) NOT NULL DEFAULT '0',
  `redirect_url` varchar(255) DEFAULT '<confirmation>',
  `status` tinyint(4) NOT NULL DEFAULT '1',
  `block` tinyint(4) NOT NULL DEFAULT '0',
  `teaser` tinyint(4) NOT NULL DEFAULT '0',
  `allow_draft` tinyint(4) NOT NULL DEFAULT '0',
  `submit_notice` tinyint(4) NOT NULL DEFAULT '1',
  `submit_text` varchar(255) DEFAULT NULL,
  `submit_limit` tinyint(4) NOT NULL DEFAULT '-1',
  `submit_interval` int(11) NOT NULL DEFAULT '-1',
  PRIMARY KEY (`nid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> alter table webform disable keys;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> show warnings;
+-------+------+-------------------------------------------------------------+
| Level | Code | Message                                                     |
+-------+------+-------------------------------------------------------------+
| Note  | 1031 | Table storage engine for 'webform' doesn't have this option |
+-------+------+-------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> select version();
+------------+
| version()  |
+------------+
| 5.5.27-log |
+------------+
1 row in set (0.00 sec)

mysql>

BEOBACHTUNG # 3

Sie haben festgestellt, dass MyISAM 20x schneller lädt als InnoDB. Möchten Sie, dass das 24-25 mal schneller ist? Führen Sie dann Folgendes aus:

ALTER TABLE item_load ROW_FORMAT=Fixed;

Dies beschleunigt INSERTs um 20-25% ohne weitere DDL-Änderungen . Nebeneffekt: Der MyISAM-Tisch kann um 80% -100% größer werden, möglicherweise auch größer.

Sie könnten dies auch auf einer InnoDB-Tabelle ausführen, aber das ACID-konforme Verhalten und der MVCC von InnoDB stellen immer noch den Leistungsengpass dar, insbesondere, wenn VARCHAR-Felder, deren Anzahl erheblich ansteigt, beschrieben werden ibdata1.

RolandoMySQLDBA
quelle
Die ersten beiden Beobachtungen waren Dinge, die ich hinzufügen wollte, um das Problem zu beheben, nachdem ich es zum ersten Mal bemerkt hatte. Mein erster Versuch war natürlich, innodb in Ruhe zu lassen (einfach die Bin-Protokollierung ausschalten). Bei der dritten Beobachtung ist meine Datengröße sehr unterschiedlich lang. Ich gehe davon aus, dass dies ein Problem sein wird. Ich habe das Gefühl, ich muss nur diesen Tisch myisam halten.
David Parks
6

Die endgültige Antwort auf diese Frage war, InnoDB nicht für eine umfangreiche Referenztabelle zu verwenden. MyISAM schreit schnell, fast der volle Durchsatz der Festplattengeschwindigkeit für die gesamte Last, InnoDB bleibt hängen. MyISAM ist einfach, aber in diesem Fall sind es auch die Anforderungen dieser Tabelle. Für eine einfache Referenztabelle mit Bulk-Ladevorgängen über LOAD DATA INFILE ist MyISAM der beste Weg.

Beachten Sie jedoch, dass bei der Ausführung von MyISAM- und InnoDB-Tabellen die Speicherzuordnung für zwei Caching-Mechanismen berücksichtigt werden muss. Jedes Modul verfügt über eine eigene eindeutige Zwischenspeicherung, die eine separate Speicherzuordnung erfordert.

David Parks
quelle
5

Sie könnten versuchen, Ihre Eingabedateien in kleinere Teile aufzuteilen.

Ich persönlich benutze dafür http://www.percona.com/doc/percona-toolkit/2.1/pt-fifo-split.html .

Was passiert, wenn Sie beim Import eine Tabellensperre für die Tabelle erhalten? Möglicherweise wird InnoDB durch das Sperren auf Zeilenebene verlangsamt (MyISAM verwendet eine Tabellensperre).

Weitere Ideen finden Sie auch hier: http://derwiki.tumblr.com/post/24490758395/loading-half-a-billion-rows-into-mysql

bnadland
quelle
Meine Dateien befinden sich bereits in 500-MB-Blöcken. Ich habe sie alle durch eine einzelne Named Pipe geleitet, um das Laden zu vereinfachen, aber ich werde diesen Ansatz jetzt ausprobieren.
David Parks
Wenn ich hier keinen Unterschied sehe, sehe ich ziemlich schnell, dass die Geschwindigkeit von einer Erweiterung der DB-Datei um 11 MB / s auf 6 MB (nach ungefähr 2 GB) abfällt und sie weiterhin abnimmt. Ich lade alle Dateien in einer for-Schleife, separate MySQL-Aufrufe.
David Parks
Die erste Datei wurde in 54s geladen, die zweite in 3m39s, die dritte in 3m9s, 4m7s, 5m21s und so weiter. Alle Dateien sind ungefähr gleich groß.
David Parks
2

Wenn Ihr PK nicht AUTO_INCREMENT ist oder die Daten in der CSV-Datei nicht nach PK sortiert sind, kann dies die Leistung des Datenladens beeinträchtigen. Da die Tabelle in MySQL ein Index ist, werden alle Daten in sortierter Reihenfolge gespeichert. Wenn der PK-Wert nicht AUTO_INCREMENT ist, muss MySQL viele Daten verschieben, um die Daten in sortierter Reihenfolge zu speichern. Dies ist der Grund für ein langsameres Laden der Daten, wenn die Tabellengröße zu wachsen beginnt.

Ich lade eine 91-GB-CSV-Datei mit PK in AUTO_INCREMENT mit LOAD DATA INFILE und sehe keinen Rückgang meines Durchsatzes. Ich erhalte 140K bis 145K Einfügungen pro Sekunde. Verwenden von Percona MySQL 5.6.38

KKYadav
quelle