2010-09-09 8 views
13

Ich arbeite mit einem riesigen Tisch, der 250 Millionen Zeilen hat. Das Schema ist einfach.MySQL Insert-Leistung verschlechtert sich auf einem großen Tisch

CREATE TABLE MyTable (
     id BIGINT PRIMARY KEY AUTO_INCREMENT, 
     oid INT NOT NULL, 
     long1 BIGINT NOT NULL, 
     str1 VARCHAR(30) DEFAULT NULL, 
     str2 VARCHAR(30) DEFAULT NULL, 
     str2 VARCHAR(200) DEFAULT NULL, 
     str4 VARCHAR(50) DEFAULT NULL, 
     int1 INT(6) DEFAULT NULL, 
     str5 VARCHAR(300) DEFAULT NULL, 
     date1 DATE DEFAULT NULL, 
     date2 DATE DEFAULT NULL, 
     lastUpdated TIMESTAMP NOT NULL, 
     hashcode INT NOT NULL, 
     active TINYINT(1) DEFAULT 1, 
     KEY oid(oid), 
     KEY lastUpdated(lastUpdated), 
     UNIQUE KEY (hashcode, active), 
     KEY (active) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 MAX_ROWS=1000000000; 

Die Leistung des Einsatzes ist deutlich gesunken. Bis zu 150 Millionen Zeilen in der Tabelle dauerte es 5-6 Sekunden, um 10.000 Zeilen einzufügen. Jetzt ist es 2-4 Mal höher gegangen. Die ibdata-Datei von Innodb ist auf 107 GB angewachsen. Innodb-Konfigurationsparameter sind wie folgt.

innodb_buffer_pool_size = 36G # Machine has 48G memory 
innodb_additional_mem_pool_size = 20M 
innodb_data_file_path = ibdata1:10M:autoextend 
innodb_log_file_size = 50M 
innodb_log_buffer_size = 20M 
innodb_log_files_in_group=2 
innodb_flush_log_at_trx_commit = 1 
innodb_lock_wait_timeout = 50 
innodb_thread_concurrency = 8 
innodb_flush_method = O_DIRECT 
expire_logs_days = 4 

IO Wartezeit ist gestiegen, wie mit top gesehen. Ich habe versucht, die Flush-Methode zu O_DSYNC zu ändern, aber es hat nicht geholfen. Die Festplatte ist aus Hardware-RAID-10-Setup geschnitzt. In einem früheren Setup mit einer einzelnen Festplatte war IO kein Problem.

Wird die Option "Nur Tabelle" partitioniert? Kann das Teilen einzelner 100G-Dateien in "kleinere" Dateien helfen? Gibt es Variablen, die auf RAID abgestimmt werden müssen?

Update: Dies ist ein Testsystem. Ich habe die Freiheit, Änderungen vorzunehmen.

Antwort

13

Sie haben nicht gesagt, ob dies ein Testsystem oder eine Produktion war; Ich nehme an, es ist Produktion.

Es ist wahrscheinlich, dass Sie die Tabelle auf eine Größe haben, wo ihre Indizes (oder die gesamte Menge) nicht mehr in den Speicher passt.

Dies bedeutet, dass InnoDB beim Einfügen Seiten lesen muss (abhängig von der Verteilung der Indexwerte der neuen Zeilen). Das Lesen von Seiten (zufällige Lesevorgänge) ist sehr langsam und sollte nach Möglichkeit vermieden werden.

Die Partitionierung scheint die offensichtlichste Lösung zu sein, aber die Partitionierung von MySQL passt möglicherweise nicht zu Ihrem Anwendungsfall.

Sie sollten sicherlich alle möglichen Optionen in Betracht ziehen - holen Sie die Tabelle auf einen Testserver in Ihrem Labor, um zu sehen, wie sie sich verhält.

Ihr Primärschlüssel sieht für mich aus, als ob es möglicherweise nicht erforderlich ist (Sie haben einen anderen eindeutigen Index), so dass das Entfernen eine Option ist.

Beachten Sie auch das Innodb-Plugin und die Komprimierung, damit Ihr innodb_buffer_pool weiter geht.

Sie müssen wirklich Ihre Anwendungsfälle analysieren, um zu entscheiden, ob Sie wirklich alle diese Daten behalten müssen und ob Partitionierung eine sinnvolle Lösung ist.

Wenn Sie Änderungen an dieser Anwendung vornehmen, wird dies wahrscheinlich zu neuen Leistungsproblemen für Ihre Benutzer führen. Daher sollten Sie hier sehr vorsichtig sein. Wenn Sie eine Möglichkeit finden, die Leistung der Einfügung zu verbessern, ist es möglich, dass die Suchleistung oder die Leistung anderer Vorgänge verringert wird. Bevor Sie eine solche Änderung vornehmen, müssen Sie einen gründlichen Leistungstest auf Hardware in Produktionsqualität durchführen.

+1

Danke, Mark. Dies ist ein Testsystem. –

+0

Ihr Tipp zur Indexgröße ist hilfreich. Ich arbeite an der Indexierung. –

2

Da MarkR oben kommentierte, wird die Leistung schlechter, wenn Indizes nicht mehr in Ihren Pufferpool passen. InnoDB hat einen zufälligen IO-Reduktionsmechanismus (der Insert-Puffer genannt wird), der einige dieser Probleme verhindert - aber es wird nicht auf Ihrem UNIQUE-Index funktionieren. Der Index auf (Hashcode, aktiv) muss bei jedem Insert überprüft werden, um sicherzustellen, dass keine doppelten Einträge eingefügt werden. Wenn der Hashcode dem Primärschlüssel nicht folgt, könnte diese Überprüfung zufällig sein.

Haben Sie die Möglichkeit, das Schema zu ändern?

Ihre beste Wette ist zu:

(a) Stellen Sie hashcode jemand sequenzielle oder sortiert nach hashcode vor Massen Einfügen (dies selbst helfen, da zufällig reduziert werden gelesen).

(b) Machen Sie (Hashcode, aktiv) den Primärschlüssel - und fügen Sie Daten in sortierter Reihenfolge ein. Ich nehme an, Ihre Anwendung liest sich wahrscheinlich mit Hashcode - und eine Primärschlüsselsuche ist schneller.

4

Aus meiner Erfahrung mit Innodb scheint es ein Limit für schreibintensive Systeme zu geben, selbst wenn Sie ein wirklich optimiertes Disk-Subsystem haben. Ich bin überrascht, dass Sie es geschafft haben, es auf 100 GB zu bringen.

Dies ist, was Twitter vor einiger Zeit traf und erkannte, dass es shard benötigt - siehe http://github.com/twitter/gizzard.

Dies hängt alles von Ihren Anwendungsfällen, aber man könnte auch von mysql zu cassandra bewegen, wie es für Schreibintensive Anwendungen wirklich gut funktioniert. (Http://cassandra.apache.org)

1

Sie nicht erwähnt wie hoch die Auslastung ist, aber wenn es nicht zu viele Lesevorgänge gibt oder genügend Hauptspeicher vorhanden ist, besteht eine andere Möglichkeit darin, anstelle von innodb ein für das Schreiben optimiertes Backend für MySQL zu verwenden. Tokutek beansprucht 18x ​​schnellere Inserts und eine viel flachere Leistungskurve, wenn das Dataset wächst.

tokutek.com

http://tokutek.com/downloads/tokudb-performance-brief.pdf

0

Ich werde zweiten @ MarkR Kommentare über die Indizes zu reduzieren. Eine andere Sache, die Sie betrachten sollten, ist Ihre innodb_log_file_size zu erhöhen. Es erhöht die Wiederherstellungszeit des Absturzes, sollte aber helfen. Beachten Sie, dass Sie die alten Dateien entfernen müssen, bevor Sie den Server neu starten.

Allgemeine InnoDB Tuning-Tipps: http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/

Sie auch bewusst LOAD DATA INFILE sein sollte Einsätze zu tun. Es ist viel schneller.

0

Zunahme von innodb_log_file_size = 50M zu innodb_log_file_size = 500M

Und die innodb_flush_log_at_trx_commit sollte 0 sein, wenn Sie 1 sec Datenverlust zu tragen.

Verwandte Themen