MySQL LOAD DATA INFILE rallenta dell'80% dopo alcuni concerti di input con il motore InnoDB


14

Sto caricando un file da 100 GB tramite LOAD DATA INFILE. Ho avuto un buon successo con MyISAM, poche ore e fatto.

Lo sto provando ora con InnoDB. Il caricamento inizia rapidamente a oltre 10 MB / sec (guardando la crescita del file della tabella, file_per_tableè attivato).

Ma dopo circa 5 GB di dati, questo rallenta fino a 2-4 MB / sec, poiché supero i 20 GB, era di circa 2 MB / sec.

La dimensione dei pool di buffer InnoDB è 8G. E ho fatto quanto segue prima di eseguire il comando LOAD DATA INFILE:

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

Non riesco a vedere il motivo per cui inizia bene e rallenta nel tempo.

Inoltre, utilizzando le stesse impostazioni, ho eseguito lo stesso comando LOAD DATA INFILE con la tabella utilizzando InnoDB e MyISAM e un set di dati di test da 5 GB, MyISAM è stato 20 volte più veloce:

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

Qualcos'altro che dovrei considerare di provare? Il motore MyISAM è in grado di mantenere molto meglio la velocità di carico.


Dettagli aggiuntivi:

  • Ho provato a caricare i file singolarmente, nessuna differenza.

  • Per inciso, ho 150 file da 500 MB ciascuno, all'interno di ogni file le chiavi sono ordinate.

  • Dopo aver ricevuto 40 GB in una notte, 12 ore dopo, la velocità di carico è scesa a 0,5 MB / sec, il che significa che l'operazione è praticamente impossibile.

  • Non ho trovato altre risposte a domande simili su altri forum, mi sembra che InnoDB non supporti il ​​caricamento di grandi quantità di dati in tabelle di dimensioni superiori a pochi GB.

Risposte:


7

OSSERVAZIONE # 1

Ho notato che hai spento autocommit. Ciò accumulerà così tanti dati in ibdata1. Perché?

Esistono sette (7) classi di informazioni archiviate in ibdata1:

  • Pagine di dati per tabelle InnoDB
  • Pagine indice per tabelle InnoDB
  • Dizionario dei dati
  • Doppio buffer di scrittura
    • Rete di sicurezza per prevenire la corruzione dei dati
    • Aiuta a bypassare il sistema operativo per la memorizzazione nella cache
  • Inserisci buffer (semplifica le modifiche agli indici secondari)
  • Segmenti di rollback
  • Annulla registri
  • Clicca qui per vedere una rappresentazione pittorica di ibdata1

Alcune di queste informazioni sono rese visibili a determinate transazioni a seconda del livello di isolamento. Tali azioni potrebbero produrre blocchi di chiave primaria non intenzionali e molti dati fantasma . Man mano che queste due cose aumentano, dovresti aspettarti un discreto rallentamento.

Raccomandazione: lasciare autocommit attivo

OSSERVAZIONE # 2

Vedo che hai questo:

alter table item_load disable keys;

DISABLE KEYS non funziona con InnoDB . Ecco perché:

  • MyISAM: DISABLE KEYSinterrompe semplicemente l'aggiornamento dell'indice secondario per la tabella MyISAM. Quando si INSERISCE in massa in una tabella MyISAM con le chiavi disabilitate si ottiene un caricamento rapido della tabella insieme a un edificio del PRIMARY KEY e di tutti gli indici univoci. Quando si esegue ENABLE KEYS, tutti gli indici secondari vengono creati linearmente sulla tabella e aggiunti al file .MYD.
  • InnoDB: come mostrato nella figura interna di InnoDB, il sistema tablepave di sistema ibdata1ha una struttura dedicata alle Inserzioni di indici secondari. Allo stato attuale, non esiste alcuna disposizione per gestire gli indici come MyISAM.

Per illustrare questo, nota il mio tentativo di eseguire DISABLE KEYS su una tabella InnoDB in 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>

OSSERVAZIONE # 3

Hai notato che MyISAM si carica 20 volte più velocemente di InnoDB. Vorresti che fosse più simile a 24-25 volte più veloce? Quindi eseguire quanto segue:

ALTER TABLE item_load ROW_FORMAT=Fixed;

Ciò consentirà di velocizzare INSERT per il 20-25% senza altre modifiche DDL . Effetto collaterale: la tabella MyISAM può aumentare dell'80% -100%, forse più grande.

È possibile eseguirlo anche su una tabella InnoDB, ma il comportamento conforme ACID e MVCC di InnoDB rimarrebbero comunque il collo di bottiglia delle sue prestazioni, soprattutto se si scrivono campi con aumento significativo dei campi VARCHAR ibdata1.


Le prime 2 osservazioni sono state cose che ho cercato di aggiungere per risolvere il problema dopo averlo notato per la prima volta, il mio primo tentativo è stato naturalmente quello di lasciare solo innodb (basta disattivare il log bin). Alla terza osservazione, la mia dimensione dei dati è molto variabile in lunghezza, suppongo che questo sarà un problema? Mi sento come se avessi solo bisogno di mantenere questo tavolo myisam.
David Parks,

6

La risposta finale a questa domanda è stata di non utilizzare InnoDB per una tabella di riferimento di massa. MyISAM sta urlando velocemente, quasi al massimo della velocità del disco per l'intero carico, InnoDB impantana. MyISAM è semplice, ma in questo caso lo sono anche i requisiti di questa tabella. Per una semplice tabella di riferimento con carichi di massa su LOAD DATA INFILE, MyISAM è la strada da percorrere, finora tutto bene.

Tuttavia, se esegui le tabelle MyISAM e InnoDB, dovrai prendere in considerazione l'allocazione della memoria per 2 meccanismi di memorizzazione nella cache, ogni motore ha la sua cache unica che richiede un'allocazione di memoria separata.


5

Potresti provare a dividere i file di input in blocchi più piccoli.

Personalmente uso http://www.percona.com/doc/percona-toolkit/2.1/pt-fifo-split.html per questo.

Cosa succede se si ottiene un blocco tabella per tabella durante l'importazione? Forse il blocco del rowlevel di InnoDB lo rallenta (MyISAM utilizza un blocco tabella).

Puoi anche leggere qui per ulteriori idee: http://derwiki.tumblr.com/post/24490758395/loading-half-a-billion-rows-into-mysql


I miei file sono già in blocchi da 500 MB, li stavo eseguendo il piping tutti attraverso una singola pipe denominata per facilitare il caricamento, ma ora proverò questo approccio.
David Parks,

Non vedendo alcuna differenza qui, abbastanza rapidamente vedo la velocità scendere dall'espansione di 11 MB / sec del file DB a 6 MB (dopo circa 2 GB) di dati e continua a diminuire. Sto caricando tutti i file in un ciclo for, chiamate mysql separate.
David Parks,

Il primo file caricato in 54s, 2o in 3m39s, 3o in 3m9s, 4m7s, 5m21s e così via. tutti i file hanno la stessa dimensione.
David Parks,

2

Se il tuo PK non è AUTO_INCREMENT o i dati nel file CSV non ordinati su PK, ciò potrebbe influire sulle prestazioni del dataload. Poiché la tabella in MySQL è un indice, quindi tutti i dati sono archiviati in ordine, se il valore PK non è su AUTO_INCREMENT di MySQL deve fare molti spostamenti di dati per ottenere i dati memorizzati in ordine. Questo è il motivo per un caricamento dei dati più lento quando le dimensioni della tabella iniziano a crescere.

Sto caricando file csv da 91 GB con PK su AUTO_INCREMENT utilizzando LOAD DATA INFILE e non vedo alcun calo nella mia velocità effettiva. Ricevo inserti da 140K a 145K al secondo. Utilizzo di Percona MySQL 5.6.38

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.