Questa domanda viene ripubblicata da Stack Overflow in base a un suggerimento nei commenti, si scusa per la duplicazione.
Domande
Domanda 1: man mano che le dimensioni della tabella del database aumentano, come posso ottimizzare MySQL per aumentare la velocità della chiamata LOAD DATA INFILE?
Domanda 2: utilizzare un cluster di computer per caricare diversi file CSV, migliorare le prestazioni o ucciderlo? (questo è il mio compito di benchmarking per domani usando i dati di carico e gli inserti di massa)
Obbiettivo
Stiamo provando diverse combinazioni di rilevatori di funzionalità e parametri di clustering per la ricerca di immagini, di conseguenza dobbiamo essere in grado di costruire e grandi database in modo tempestivo.
Informazioni sulla macchina
La macchina ha 256 gig di ram e ci sono altre 2 macchine disponibili con la stessa quantità di ram se c'è un modo per migliorare i tempi di creazione distribuendo il database?
Schema della tabella
sembra lo schema della tabella
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| match_index | int(10) unsigned | NO | PRI | NULL | |
| cluster_index | int(10) unsigned | NO | PRI | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| tfidf | float | NO | | 0 | |
+---------------+------------------+------+-----+---------+----------------+
creato con
CREATE TABLE test
(
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL AUTO_INCREMENT,
tfidf FLOAT NOT NULL DEFAULT 0,
UNIQUE KEY (id),
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
Benchmarking finora
Il primo passo è stato quello di confrontare inserimenti di massa vs caricamento da un file binario in una tabella vuota.
It took: 0:09:12.394571 to do 4,000 inserts with 5,000 rows per insert
It took: 0:03:11.368320 seconds to load 20,000,000 rows from a csv file
Data la differenza di prestazioni che ho seguito con il caricamento dei dati da un file csv binario, per prima cosa ho caricato file binari contenenti file da 100K, 1M, 20M, 200M usando la chiamata in basso.
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;
Ho eliminato il caricamento del file binario di 200 m di file (file csv di ~ 3 GB) dopo 2 ore.
Quindi ho eseguito uno script per creare la tabella e inserire diversi numeri di righe da un file binario, quindi rilasciare la tabella, vedere il grafico seguente.
Ci sono voluti circa 7 secondi per inserire 1 milione di righe dal file binario. Successivamente ho deciso di eseguire il benchmark inserendo 1M righe alla volta per vedere se ci sarebbe stato un collo di bottiglia in una dimensione del database particolare. Una volta che il database ha raggiunto circa 59 milioni di righe, il tempo medio di inserimento è sceso a circa 5.000 / secondo
L'impostazione del key_buffer_size globale = 4294967296 ha migliorato leggermente le velocità per l'inserimento di file binari più piccoli. Il grafico seguente mostra le velocità per diversi numeri di righe
Tuttavia, per l'inserimento di righe 1M non ha migliorato le prestazioni.
righe: 1.000.000 di tempo: 0: 04: 13.761428 inserti / sec: 3.940
vs per un database vuoto
righe: 1.000.000 di tempo: 0: 00: 6.339295 inserti / sec: 315.492
Aggiornare
Esecuzione dei dati di caricamento utilizzando la sequenza seguente rispetto al solo utilizzo del comando load data
SET autocommit=0;
SET foreign_key_checks=0;
SET unique_checks=0;
LOAD DATA INFILE '/mnt/imagesearch/tests/eggs.csv' INTO TABLE test_ClusterMatches;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
Quindi questo sembra abbastanza promettente in termini di dimensioni del database che viene generato ma le altre impostazioni non sembrano influenzare le prestazioni della chiamata di caricamento dei dati di caricamento.
Ho quindi provato a caricare più file da macchine diverse ma il comando di caricamento dei dati di caricamento blocca la tabella, a causa delle grandi dimensioni dei file che causano il timeout delle altre macchine con
ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction
Aumentando il numero di righe nel file binario
rows: 10,000,000 seconds rows: 0:01:36.545094 inserts/sec: 103578.541236
rows: 20,000,000 seconds rows: 0:03:14.230782 inserts/sec: 102970.29026
rows: 30,000,000 seconds rows: 0:05:07.792266 inserts/sec: 97468.3359978
rows: 40,000,000 seconds rows: 0:06:53.465898 inserts/sec: 96743.1659866
rows: 50,000,000 seconds rows: 0:08:48.721011 inserts/sec: 94567.8324859
rows: 60,000,000 seconds rows: 0:10:32.888930 inserts/sec: 94803.3646283
Soluzione: pre-calcolare l'id al di fuori di MySQL invece di utilizzare l'incremento automatico
Costruire il tavolo con
CREATE TABLE test (
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL ,
tfidf FLOAT NOT NULL DEFAULT 0,
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
con l'SQL
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"
Ottenere lo script per pre-calcolare gli indici sembra aver rimosso l'hit di prestazioni man mano che il database aumenta di dimensioni.
Aggiornamento 2: utilizzo delle tabelle di memoria
Circa 3 volte più veloce, senza tenere conto del costo dello spostamento di una tabella in memoria su una tabella basata su disco.
rows: 0 seconds rows: 0:00:26.661321 inserts/sec: 375075.18851
rows: 10000000 time: 0:00:32.765095 inserts/sec: 305202.83857
rows: 20000000 time: 0:00:38.937946 inserts/sec: 256818.888187
rows: 30000000 time: 0:00:35.170084 inserts/sec: 284332.559456
rows: 40000000 time: 0:00:33.371274 inserts/sec: 299658.922222
rows: 50000000 time: 0:00:39.396904 inserts/sec: 253827.051994
rows: 60000000 time: 0:00:37.719409 inserts/sec: 265115.500617
rows: 70000000 time: 0:00:32.993904 inserts/sec: 303086.291334
rows: 80000000 time: 0:00:33.818471 inserts/sec: 295696.396209
rows: 90000000 time: 0:00:33.534934 inserts/sec: 298196.501594
caricando i dati in una tabella basata sulla memoria e quindi copiandoli in una tabella basata sul disco in blocchi, si è avuto un sovraccarico di 10 min 59,71 secondi per copiare 107.356.741 righe con la query
insert into test Select * from test2;
che richiede circa 15 minuti per caricare 100 milioni di righe, che è approssimativamente lo stesso che inserirlo direttamente in una tabella basata su disco.
id
dovrebbe essere più veloce. (Anche se penso che non lo stia cercando)