2013-08-03 20 views
7

Pracuję nad dużą bazą danych MySQL i muszę poprawić wydajność INSERT w konkretnej tabeli. Ten zawiera około 200 milionów wierszy, a jego struktura jest następująca:Jak poprawić wydajność INSERT na bardzo dużej tabeli MySQL

(małe założenie: nie jestem ekspertem od bazy danych, więc napisany przeze mnie kod mógłby opierać się na niewłaściwych fundamentach.) Proszę, pomóż mi zrozumieć błędy :))

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; 

codziennie otrzymuję wiele plików csv, w którym każda linia składa się z pary „nazwa; klucz”, więc mam do analizowania tych plików (dodawanie wartości created_at i updated_at dla każdego wiersza) i wstaw wartości do mojej tabeli. W tym jednym, kombinacja „nazwa” i „klucz” musi być niepowtarzalny, tak I wdrożone procedury wstawiania następująco:

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; 

Kod właśnie pokazano pozwala mi osiągnąć mój cel, ale do zakończenia realizacji , zatrudnia około 48 godzin, a to jest problem. Myślę, że ta słaba wydajność wynika z faktu, że skrypt musi sprawdzić na bardzo dużej tabeli (200 milionów wierszy) i dla każdego wstawienia, że ​​para "nazwa, klucz" jest unikalna.

Jak mogę poprawić wydajność mojego skryptu?

Dziękuję wszystkim z góry.

Odpowiedz

2

Twój klucz liniowy na nazwę i duże indeksy spowalniają działanie.

KLUCZ LINIOWY musi być obliczany dla każdej wstawki. http://dev.mysql.com/doc/refman/5.1/en/partitioning-linear-hash.html

czy możesz pokazać nam przykładowe dane pliku file_to_process.csv może lepiej skompilować lepszy schemat.

Edit wyglądał bardziej ściśle

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 
) 

będzie proberly będzie utworzyć tabelę temp dysku, to jest bardzo powolny, więc nie należy go używać, aby uzyskać większą wydajność, a może warto sprawdzić niektóre ustawienia mysql konfiguracyjnych, takich jak tmp-table-size i max-heap-table-size mogą być źle skonfigurowane.

-2

Można użyć

load data local infile '' 
REPLACE 
into table 

etc ...

REPLACE zapewniają, że każdy duplikat wartość jest zastępowane nowymi wartościami. Dodaj na koniec końcówkę SET updated_at=now() i gotowe.

Nie ma potrzeby stosowania tabeli tymczasowej.

1

Możesz skorzystać z następujących metod w celu przyspieszenia wkładki:

  1. Jeśli wstawiasz wiele wierszy z tego samego klienta w tym samym czasie, oświadczenia stosowanie INSERT z wielu wartości wymienia wstawić kilka wierszy na czas. Jest to znacznie szybsze (w wielu przypadkach wielokrotnie szybsze) niż użycie oddzielnych jednorzędowych instrukcji INSERT.Jeśli dodajesz dane do niepustej tabeli, możesz dostroić zmienną bulk_insert_buffer_size, aby przyspieszyć wstawianie danych.

  2. Podczas ładowania tablicę z pliku tekstowego, użyj LOAD DATA plik_we. Zwykle jest to 20 razy szybsze niż przy użyciu instrukcji INSERT.

  3. Skorzystaj z faktu, że kolumny mają wartości domyślne. Wstaw wartości jawnie tylko wtedy, gdy wartość do wstawienia różni się od domyślnej. Zmniejsza to parsowanie, które musi wykonać MySQL, i poprawia szybkość wstawiania.

Powiązane problemy