it-swarm.com.de

Tabelle mit 80 Millionen Datensätzen und Hinzufügen eines Indexes dauert mehr als 18 Stunden (oder für immer)! Was jetzt?

Eine kurze Zusammenfassung des Geschehens. Ich arbeite mit 71 Millionen Datensätzen (nicht viel im Vergleich zu Milliarden von Datensätzen, die von anderen verarbeitet werden). Auf einem anderen Thread hat jemand vorgeschlagen, dass das aktuelle Setup meines Clusters nicht für meine Bedürfnisse geeignet ist. Meine Tischstruktur ist:

CREATE TABLE `IPAddresses` (
  `id` int(11) unsigned NOT NULL auto_increment,
  `ipaddress` bigint(20) unsigned default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM;

Und ich habe die 71 Millionen Datensätze hinzugefügt und dann ein:

ALTER TABLE IPAddresses ADD INDEX(ipaddress);

Es ist 14 Stunden her und die Operation ist immer noch nicht abgeschlossen. Beim Googeln habe ich festgestellt, dass es einen bekannten Ansatz gibt, um dieses Problem zu lösen - die Partitionierung. Ich verstehe, dass ich meine Tabelle jetzt basierend auf der IP-Adresse partitionieren muss. Kann ich dies tun, ohne die gesamte Tabelle neu zu erstellen? Ich meine, durch eine ALTER-Anweisung? Wenn ja, gab es eine Anforderung, die besagte, dass die zu partitionierende Spalte ein Primärschlüssel sein sollte. Ich werde die ID dieser IP-Adresse beim Erstellen einer anderen Tabelle verwenden, sodass IP-Adresse nicht mein Primärschlüssel ist. Wie partitioniere ich meine Tabelle in diesem Szenario?

29
Legend

Ok stellt sich heraus, dass dieses Problem mehr war als nur eine einfache Erstellung einer Tabelle, Indexierung und vergessenes Problem :) Hier ist, was ich getan habe, falls jemand anderes das gleiche Problem hat (ich habe ein Beispiel für eine IP-Adresse verwendet, aber es funktioniert für andere Datentypen auch):

Problem: Ihre Tabelle enthält Millionen von Einträgen und Sie müssen einen Index sehr schnell hinzufügen

Usecase: Speichern Sie Millionen von IP-Adressen in einer Nachschlagetabelle. Das Hinzufügen der IP-Adressen sollte kein großes Problem sein, aber das Erstellen eines Index für sie dauert mehr als 14 Stunden. 

Solution: Partitionieren Sie Ihre Tabelle mit MySQLs Partitionin g-Strategie

Fall # 1: Wenn die gewünschte Tabelle noch nicht erstellt wurde

CREATE TABLE IPADDRESSES(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  ipaddress BIGINT UNSIGNED,
  PRIMARY KEY(id, ipaddress)
) ENGINE=MYISAM
PARTITION BY HASH(ipaddress)
PARTITIONS 20;

Fall # 2: Wenn die gewünschte Tabelle bereits erstellt wurde. Es scheint einen Weg zu geben, ALTER TABLE dazu zu verwenden, aber ich habe noch keine geeignete Lösung dafür gefunden. Stattdessen gibt es eine etwas ineffiziente Lösung:

CREATE TABLE IPADDRESSES_TEMP(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  ipaddress BIGINT UNSIGNED,
  PRIMARY KEY(id)
) ENGINE=MYISAM;

Tragen Sie Ihre IP-Adressen in diese Tabelle ein. Und dann erstellen Sie die eigentliche Tabelle mit Partitionen:

CREATE TABLE IPADDRESSES(
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  ipaddress BIGINT UNSIGNED,
  PRIMARY KEY(id, ipaddress)
) ENGINE=MYISAM
PARTITION BY HASH(ipaddress)
PARTITIONS 20;

Und dann endlich

INSERT INTO IPADDRESSES(ipaddress) SELECT ipaddress FROM IPADDRESSES_TEMP;
DROP TABLE IPADDRESSES_TEMP;
ALTER TABLE IPADDRESSES ADD INDEX(ipaddress)

Und los geht's ... für die Indizierung der neuen Tabelle habe ich auf einer 3,2-GHz-Maschine mit 1 GB RAM etwa 2 Stunden gebraucht :) Hoffe, das hilft.

37
Legend

Das Erstellen von Indizes mit MySQL ist langsam, aber nicht so langsam. Mit 71 Millionen Datensätzen sollte es einige Minuten dauern, nicht 14 Stunden. Mögliche Probleme sind:

  • sie haben keine Sortierpuffergrößen und andere Konfigurationsoptionen konfiguriert

schauen Sie hier: http://dev.mysql.com/doc/refman/5.5/de/server-systemvariablen.html#sysvar_myisam_sort_buffer_size

Wenn Sie versuchen, einen 1-GB-Index mit einem 8-MB-Sortierpuffer zu generieren, werden viele Durchläufe benötigt. Ist der Puffer jedoch größer als der CPU-Cache, wird er langsamer. Sie müssen also testen und sehen, was am besten funktioniert.

  • jemand hat eine Sperre für den Tisch
  • ihr IO System ist scheiße
  • ihr Server wechselt
  • usw

Überprüfen Sie wie üblich iostat, vmstat, Protokolle usw. Setzen Sie eine LOCK TABLE für Ihre Tabelle ab, um zu prüfen, ob jemand eine Sperre hat.

FYI auf meinem 64-Bit-Desktop, der einen Index für 10M zufällige BIGINTs erstellt, dauert 17 Sekunden ...

7
peufeu

Ich hatte das Problem, dass ich meine Abfrage durch Hinzufügen eines Index beschleunigen wollte. Der Tisch hatte nur etwa 300.000 Datensätze, aber es dauerte auch viel zu lange. Bei der Überprüfung der Serverprozesse von mysql stellte sich heraus, dass die Abfrage, die ich optimieren wollte, immer noch im Hintergrund ausgeführt wurde. 4 Mal! Nachdem ich diese Abfragen getötet hatte, erfolgte die Indexierung in einem Handgriff. Möglicherweise trifft das gleiche Problem auf Ihre Situation zu.

5
Giel Berkers

Sie verwenden MyISAM, das bald nicht mehr verwendet wird. Eine Alternative wäre InnoDB.

"InnoDB ist eine transaktionssichere (ACID-kompatible) Speicher-Engine für MySQL, die Commit-, Rollback- und Crash-Recovery-Funktionen zum Schutz von Benutzerdaten bietet. InnoDB-Sperren auf Zeilenebene (ohne Eskalation zu gröberen Granularitätssperren) und konsistentes Oracle-style Nonlocking Durch Lesevorgänge wird die Mehrbenutzer-Parallelität und -Leistung erhöht. InnoDB speichert Benutzerdaten in Clustered-Indizes, um die E/A für häufige Abfragen auf der Basis von Primärschlüsseln zu reduzieren. Um die Datenintegrität aufrechtzuerhalten, unterstützt InnoDB auch FOREIGN KEY-Einschränkungen für die referenzielle Integrität mit Tabellen aus anderen MySQL-Speicher-Engines, auch innerhalb derselben Anweisung. "\

http://dev.mysql.com/doc/refman/5.0/de/innodb.html

Gemäß:

http://dev.mysql.com/tech-resources/articles/storage-engine/part_1.html

, Sie sollten in der Lage sein, zwischen verschiedenen Motoren zu wechseln, indem Sie einen einfachen Änderungsbefehl verwenden, der Ihnen einige Flexibilität gibt. Es gibt auch an, dass jede Tabelle in Ihrer Datenbank unabhängig konfiguriert werden kann.

3
Michael Eakins

In deinem Tisch Sie haben bereits 71 Milliarden Datensätze eingefügt. Wenn Sie jetzt Partitionen in der Primärschlüsselspalte Ihrer Tabelle erstellen möchten, können Sie die Option alter table verwenden. Ein Beispiel dient als Referenz.

CREATE TABLE t1 (
    id INT,
    year_col INT
);

ALTER TABLE t1
    PARTITION BY HASH(id)
    PARTITIONS 8;
0
seema