2013-08-03 2 views
7

Ich arbeite an einer großen MySQL-Datenbank und muss die INSERT-Leistung für eine bestimmte Tabelle verbessern. Dieser enthält ungefähr 200 Millionen Zeilen und seine Struktur ist wie folgt:Wie verbessert man die INSERT-Leistung bei einer sehr großen MySQL-Tabelle?

(eine kleine Prämisse: Ich bin kein Datenbankexperte, also könnte der Code, den ich geschrieben habe, auf falschen Grundlagen basieren. Bitte helfen Sie mir, meine zu verstehen Fehler :))

CREATE TABLE IF NOT EXISTS items (
    id INT NOT NULL AUTO_INCREMENT, 
    name VARCHAR(200) NOT NULL, 
    key VARCHAR(10) NOT NULL, 
    busy TINYINT(1) NOT NULL DEFAULT 1, 
    created_at DATETIME NOT NULL, 
    updated_at DATETIME NOT NULL, 

    PRIMARY KEY (id, name), 
    UNIQUE KEY name_key_unique_key (name, key), 
    INDEX name_index (name) 
) ENGINE=MyISAM 
PARTITION BY LINEAR KEY(name) 
PARTITIONS 25; 

jeden Tag habe ich viele csv-Dateien erhalten, in denen jede Zeile durch das Paar zusammengesetzt ist „name; Schlüssel“, also muss ich diese Dateien analysieren (Werte created_at und updated_at für jede Zeile hinzugefügt) und füge die Werte in meine Tabelle ein. In diesem Fall, muss die Kombination von „name“ und „Schlüssel“ sein UNIQUE, so implementiert ich das Insert wie folgt vorgegangen:

CREATE TEMPORARY TABLE temp_items (
    id INT NOT NULL AUTO_INCREMENT, 
    name VARCHAR(200) NOT NULL, 
    key VARCHAR(10) NOT NULL, 
    busy TINYINT(1) NOT NULL DEFAULT 1, 
    created_at DATETIME NOT NULL, 
    updated_at DATETIME NOT NULL, 
    PRIMARY KEY (id) 
    ) 
ENGINE=MyISAM; 

LOAD DATA LOCAL INFILE 'file_to_process.csv' 
INTO TABLE temp_items 
FIELDS TERMINATED BY ',' 
OPTIONALLY ENCLOSED BY '\"' 
(name, key, created_at, updated_at); 

INSERT INTO items (name, key, busy, created_at, updated_at) 
(
    SELECT temp_items.name, temp_items.key, temp_items.busy, temp_items.created_at, temp_items.updated_at 
    FROM temp_items 
) 
ON DUPLICATE KEY UPDATE busy=1, updated_at=NOW(); 

DROP TEMPORARY TABLE temp_items; 

Der Code nur erlaubt mir gezeigt, mein Ziel zu erreichen, aber die Ausführung abzuschließen Es dauert etwa 48 Stunden, und das ist ein Problem. Ich denke, dass diese schlechte Leistung durch die Tatsache verursacht werden, dass das Skript eine sehr große Tabelle (200 Millionen Zeilen) überprüfen muss und für jede Einfügung, dass das Paar "Name; Schlüssel" eindeutig ist.

Wie kann ich die Leistung meines Skripts verbessern?

Vielen Dank an alle im Voraus.

Antwort

2

Ihr linearer Schlüssel auf Name und die großen Indizes verlangsamt die Dinge.

LINEARSCHLÜSSEL muss für jeden Einsatz berechnet werden. http://dev.mysql.com/doc/refman/5.1/en/partitioning-linear-hash.html

können Sie uns einige Beispieldaten von file_to_process.csv zeigen, vielleicht sollte ein besseres Schema erstellt werden.

bearbeiten sah genauer

INSERT INTO items (name, key, busy, created_at, updated_at) 
(
    SELECT temp_items.name, temp_items.key, temp_items.busy, temp_items.created_at, temp_items.updated_at 
    FROM temp_items 
) 

diese proberly wird eine Platte temporäre Tabelle erstellen, ist dies sehr, sehr langsam, so dass Sie sollten es nicht mehr Leistung nutzen zu bekommen oder vielleicht sollten Sie einige mysql Konfigurationseinstellungen überprüfen wie tmp-table-size und max-heap-table-size sind diese möglicherweise falsch konfiguriert.

0

Es gibt eine Dokumentation, die ich hervorheben möchte, .

-2

könnten Sie

load data local infile '' 
REPLACE 
into table 

etc ...

Die REPLACE gewährleisten verwenden, dass jeder doppelten Wert mit den neuen Werten überschrieben. Fügen Sie am Ende ein SET updated_at=now() hinzu und Sie sind fertig.

Die temporäre Tabelle ist nicht erforderlich.

1

Sie können die folgenden Methoden verwenden Einsätze zu beschleunigen:

  1. Wenn Sie viele Zeilen vom selben Client zur gleichen Zeit einfügen, Verwendung INSERT-Anweisungen mit mehreren Werten listen mehrere Zeilen in einer einfügen Zeit. Dies ist erheblich schneller (in manchen Fällen um ein Vielfaches schneller) als die Verwendung einzelner INSERT-Anweisungen mit einer Zeile.Wenn Sie Daten zu einer nicht leeren Tabelle hinzufügen, können Sie die Variable bulk_insert_buffer_size anpassen, um das Einfügen von Daten noch schneller zu machen.

  2. Wenn Sie eine Tabelle aus einer Textdatei laden, verwenden Sie LOAD DATA INFILE. Dies ist normalerweise 20 mal schneller als die Verwendung von INSERT-Anweisungen.

  3. Nutzen Sie die Tatsache, dass Spalten Standardwerte haben. Fügen Sie Werte nur dann explizit ein, wenn der einzufügende Wert vom Standardwert abweicht. Dies reduziert das Parsing, das MySQL durchführen muss, und verbessert die Geschwindigkeit des Einfügevorgangs.

Verwandte Themen