MySQL LOAD DATA INFILE zwalnia o 80% po kilku koncertach z silnikiem InnoDB

14

Ładuję plik 100 GB przez LOAD DATA INFILE. Miałem dobry sukces z MyISAM, kilka godzin i skończyłem.

Próbuję teraz, używając InnoDB. Ładowanie rozpoczyna się szybko przy prędkości ponad 10 MB / s (obserwowanie wzrostu pliku tabeli file_per_tablejest włączone).

Ale po około 5 GB danych spowalnia do zakresu 2-4 MB / s, a gdy otrzymuję ponad 20 GB, spada o około 2 MB / s.

Rozmiar pul buforów InnoDB wynosi 8G. Przed uruchomieniem polecenia LOAD DATA INFILE wykonałem następujące czynności:

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....

Nie widzę powodu, dla którego zaczyna się dobrze i zwalnia.

Ponadto, używając tych samych ustawień, uruchomiłem to samo polecenie LOAD DATA INFILE z tabelą przy użyciu InnoDB i MyISAM oraz testowym zestawem danych 5 GB, MyISAM był 20 razy szybszy:

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

Coś jeszcze powinienem rozważyć? Silnik MyISAM jest w stanie znacznie lepiej utrzymać szybkość ładowania.


Dodatkowe Szczegóły:

  • Próbowałem ładować pliki indywidualnie, bez różnicy.

  • Nawiasem mówiąc, mam 150 plików po 500 MB każdy, w każdym pliku klucze są posortowane.

  • Po uzyskaniu 40 GB w ciągu nocy, 12 godzin później, szybkość ładowania spadła do 0,5 MB / s, co oznacza, że ​​operacja jest praktycznie niemożliwa.

  • Nie znalazłem żadnych innych odpowiedzi na podobne pytania na innych forach, wydaje mi się, że InnoDB nie obsługuje ładowania dużych ilości danych do tabel o wielkości kilku GB.

David Parks
źródło

Odpowiedzi:

7

OBSERWACJA # 1

Zauważyłem, że się wyłączyłeś autocommit. To zgromadzi tyle danych w ibdata1. Dlaczego?

Istnieje siedem (7) klas informacji przechowywanych w ibdata1:

  • Strony danych dla tabel InnoDB
  • Strony indeksu dla tabel InnoDB
  • Słownik danych
  • Podwójny bufor zapisu
    • Siatka bezpieczeństwa zapobiegająca uszkodzeniu danych
    • Pomaga ominąć system operacyjny dla buforowania
  • Wstaw bufor (usprawnia zmiany w indeksach wtórnych)
  • Wycofywanie segmentów
  • Cofnij dzienniki
  • Kliknij tutaj, aby zobaczyć obrazowe przedstawienie ibdata1

Niektóre z tych informacji są widoczne dla niektórych transakcji w zależności od poziomu izolacji. Takie działania mogą spowodować niezamierzone blokady kluczy głównych i wiele danych fantomowych . Gdy te dwie rzeczy rosną, należy spodziewać się spowolnienia.

Zalecenie: pozostaw automatyczne zatwierdzanie

OBSERWACJA # 2

Widzę, że masz to:

alter table item_load disable keys;

DISABLE KEYS nie działa z InnoDB . Oto dlaczego:

  • MyISAM: DISABLE KEYSpo prostu wyłącza aktualizację indeksu dodatkowego dla tabeli MyISAM. Kiedy wprowadzisz INSERT do tabeli MyISAM z wyłączonymi kluczami, powoduje to szybkie ładowanie tabeli wraz z budowaniem KLUCZA PODSTAWOWEGO i wszystkich unikalnych indeksów. Po uruchomieniu ENABLE KEYSwszystkie indeksy dodatkowe są budowane liniowo na stole i dołączane do .MYD.
  • InnoDB: Jak pokazano na wewnętrznym obrazie InnoDB, systemowa tablica tabel ibdata1ma strukturę dedykowaną wstawianiu indeksu wtórnego. Obecnie nie ma przepisu do obsługi indeksów takich samych jak MyISAM.

Aby to zilustrować, zwróć uwagę na moją próbę uruchomienia DISABLE KEYS w tabeli InnoDB w MySQL

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>

OBSERWACJA # 3

Zauważyłeś, że MyISAM ładuje się 20 razy szybciej niż InnoDB. Czy chciałbyś, żeby było to 24-25 razy szybsze? Następnie uruchom następujące czynności:

ALTER TABLE item_load ROW_FORMAT=Fixed;

Przyspieszy to WSTAWIANIE razy 20-25% bez żadnych innych zmian DDL . Efekt uboczny: stół MyISAM może powiększać się o 80% -100%, być może nawet większy.

Można to również uruchomić na tabeli InnoDB, ale zachowanie zgodne z ACID i MVCC InnoDB nadal będzie wąskim gardłem jego wydajności, szczególnie jeśli zapisywane są znaczące wzrosty pól VARCHAR ibdata1.

RolandoMySQLDBA
źródło
Pierwsze 2 obserwacje były rzeczami, które starałem się dodać, aby rozwiązać problem po tym, jak to zauważyłem, moją pierwszą próbą było oczywiście pozostawienie innodb w spokoju (po prostu wyłącz rejestrowanie bin). Przy trzeciej obserwacji mój rozmiar danych jest bardzo zmienny, zakładam, że to będzie problem? Czuję, że muszę po prostu zachować ten stolik.
David Parks,
6

Ostateczną odpowiedzią na to pytanie było nieużywanie programu InnoDB do stworzenia ogromnej tabeli referencyjnej. MyISAM krzyczy szybko, prawie pełna przepustowość prędkości dysku dla całego obciążenia, InnoDB zapada w dół. MyISAM jest prosty, ale w tym przypadku tak samo jest z wymaganiami tej tabeli. Jeśli chodzi o prostą tabelę referencyjną z ładunkami masowymi przez LOAD DATA INFILE, MyISAM to droga, do tej pory tak dobra.

Pamiętaj jednak, że jeśli uruchomisz tabele MyISAM i InnoDB, musisz rozważyć przydzielenie pamięci dla 2 mechanizmów buforowania, każdy silnik ma swoje własne buforowanie, które wymaga oddzielnego przydzielenia pamięci.

David Parks
źródło
5

Możesz spróbować podzielić swoje pliki wejściowe na mniejsze części.

Ja osobiście korzystam z http://www.percona.com/doc/percona-toolkit/2.1/pt-fifo-split.html w tym celu.

Co się stanie, jeśli podczas importu zostanie zablokowana tabela? Być może blokowanie InnoDB na poziomie wiersza spowalnia go (MyISAM używa blokady tabeli).

Możesz również przeczytać tutaj, aby uzyskać dalsze pomysły: http://derwiki.tumblr.com/post/24490758395/loading-half-a-billion-rows-into-mysql

bnadland
źródło
Moje pliki są już w porcjach po 500 MB, przepuszczałem je wszystkie przez jedną nazwaną potok, aby ułatwić ładowanie, ale spróbuję teraz tego podejścia.
David Parks
Nie widząc tutaj żadnej różnicy, dość szybko widzę spadek prędkości z powiększania pliku DB o 11 MB / s do 6 MB (po około 2 GB) danych i nadal spada. Ładuję wszystkie pliki w pętli for, osobne wywołania mysql.
David Parks
Pierwszy plik załadowany w 54s, drugi w 3m39s, trzeci w 3m9s, 4m7s, 5m21s i tak dalej. wszystkie pliki mają ten sam rozmiar.
David Parks,
2

Jeśli twój PK nie jest AUTO_INCREMENT lub dane w pliku csv nie są posortowane na PK, może to mieć wpływ na wydajność ładowania danych. Ponieważ tabela w MySQL jest indeksem, dlatego wszystkie dane są przechowywane w posortowanej kolejności, jeśli wartość PK nie jest ustawiona na AUTO_INCREMENT, wówczas MySQL musi wykonać wiele przesunięć danych, aby dane były przechowywane w posortowanej kolejności. Jest to powód wolniejszego ładowania danych, gdy rozmiar tabeli zaczyna rosnąć.

Ładuję plik CSV 91 GB z PK na AUTO_INCREMENT przy użyciu LOAD DATA INFILE i nie widzę żadnego spadku mojej przepustowości. Dostaję od 140 KB do 145 000 wstawek na sekundę. Korzystanie z Percona MySQL 5.6.38

KKYadav
źródło