Esta pergunta foi publicada novamente no Stack Overflow com base em uma sugestão nos comentários, desculpas pela duplicação.
Questões
Pergunta 1: à medida que o tamanho da tabela do banco de dados aumenta, como posso ajustar o MySQL para aumentar a velocidade da chamada LOAD DATA INFILE?
Pergunta 2: usaria um cluster de computadores para carregar arquivos csv diferentes, melhorar o desempenho ou eliminá-lo? (esta é minha tarefa de marcação de benchmarking para amanhã usando os dados de carregamento e as inserções em massa)
Objetivo
Estamos testando diferentes combinações de detectores de recursos e parâmetros de agrupamento para pesquisa de imagens, como resultado, precisamos poder construir e grandes bancos de dados em tempo hábil.
Informações da máquina
A máquina possui 256 GB de RAM e existem outras 2 máquinas disponíveis com a mesma quantidade de RAM, se houver uma maneira de melhorar o tempo de criação distribuindo o banco de dados?
Esquema de tabela
o esquema da tabela se parece
+---------------+------------------+------+-----+---------+----------------+
| 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 | |
+---------------+------------------+------+-----+---------+----------------+
criado com
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 até agora
O primeiro passo foi comparar as inserções em massa e o carregamento de um arquivo binário em uma tabela vazia.
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
Dada a diferença de desempenho, eu carreguei os dados de um arquivo csv binário, primeiro carreguei arquivos binários contendo 100K, 1M, 20M, 200M linhas usando a chamada abaixo.
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;
Eu matei o carregamento do arquivo binário de 200 milhões de linhas (~ arquivo de 3 GB csv) após 2 horas.
Então, eu executei um script para criar a tabela e insira diferentes números de linhas de um arquivo binário e depois solte a tabela, veja o gráfico abaixo.
Demorou cerca de 7 segundos para inserir 1 milhão de linhas do arquivo binário. Em seguida, decidi comparar a inserção de 1 milhão de linhas por vez para verificar se haveria um gargalo em um tamanho de banco de dados específico. Depois que o banco de dados atinge aproximadamente 59 milhões de linhas, o tempo médio de inserção cai para aproximadamente 5.000 / segundo
A configuração do key_buffer_size global = 4294967296 melhorou ligeiramente as velocidades para inserir arquivos binários menores. O gráfico abaixo mostra as velocidades para diferentes números de linhas
No entanto, para inserir linhas de 1 milhão, não melhorou o desempenho.
linhas: 1.000.000 de tempo: 0: 04: 13.761428 inserções / s: 3.940
vs para um banco de dados vazio
linhas: 1.000.000 de tempo: 0: 00: 6.339295 inserções / s: 315.492
Atualizar
Executando o Carregamento de Dados Utilizando a Sequência a seguir vs Apenas Utilizando o 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;
Portanto, isso parece bastante promissor em termos do tamanho do banco de dados que está sendo gerado, mas as outras configurações não parecem afetar o desempenho da chamada de infile de carregamento de dados.
Tentei carregar vários arquivos de máquinas diferentes, mas o comando load data infile bloqueia a tabela, devido ao tamanho grande dos arquivos, causando o tempo limite das outras máquinas
ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction
Aumentando o número de linhas no arquivo binário
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
Solução: Pré-computando o ID fora do MySQL em vez de usar o incremento automático
Construindo a mesa com
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;
com o SQL
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"
Conseguir que o script pré-calcule os índices parece ter removido o impacto no desempenho à medida que o banco de dados aumenta de tamanho.
Atualização 2 - usando tabelas de memória
Aproximadamente três vezes mais rápido, sem levar em conta o custo de mover uma tabela na memória para uma tabela baseada em 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
carregar os dados em uma tabela baseada em memória e copiá-los para uma tabela baseada em disco em pedaços teve uma sobrecarga de 10 min 59,71 segundos para copiar 107.356.741 linhas com a consulta
insert into test Select * from test2;
o que leva aproximadamente 15 minutos para carregar 100 milhões de linhas, o que é aproximadamente o mesmo que inseri-lo diretamente em uma tabela baseada em disco.
id
deveria ser mais rápido. (Embora eu acho que você não está olhando para isso)