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)Respostas:
Boa pergunta - bem explicada.
Você já tem uma configuração alta (ish) para o buffer de chave - mas é suficiente? Estou assumindo que esta é uma instalação de 64 bits (caso contrário, a primeira coisa que você precisa fazer é atualizar) e não está executando no MSNT. Dê uma olhada na saída do mysqltuner.pl depois de executar alguns testes.
Para usar o cache da melhor maneira possível, você pode encontrar benefícios ao agrupar / pré-classificar os dados de entrada (as versões mais recentes do comando 'sort' têm muita funcionalidade para classificar grandes conjuntos de dados). Além disso, se você gerar os números de identificação fora do MySQL, poderá ser mais eficiente.
Supondo (novamente) que você deseja que a saída definida se comporte como uma única tabela, os únicos benefícios que você terá são distribuir o trabalho de classificação e geração de IDs - para os quais você não precisa de mais bancos de dados. OTOH usando um cluster de banco de dados, você terá problemas com a contenção (que não devem ser vistos como problemas de desempenho).
Se você pode fragmentar os dados e manipular os conjuntos de dados resultantes independentemente, então sim, obterá benefícios de desempenho - mas isso não nega a necessidade de ajustar cada nó.
Verifique se você tem pelo menos 4 Gb para o tamanho sort_buffer_size.
Além disso, o fator limitante do desempenho é a E / S do disco. Há várias maneiras de resolver isso - mas você provavelmente deve considerar um conjunto espelhado de conjuntos de dados distribuídos em SSDs para obter o desempenho ideal.
fonte
load data...
é mais rápido que inserir, então use isso.Se você quer ser realmente eficiente, pode criar um programa multithread para alimentar um único arquivo em uma coleção de pipes nomeados e gerenciar as instâncias de inserção.
Em resumo, você não ajusta o MySQL tanto quanto ajusta sua carga de trabalho ao MySQL.
fonte
Não me lembro exatamente da sintaxe, mas se for inno db, você pode desativar a verificação de chave estrangeira.
Além disso, você pode criar o índice após a importação, pode ser realmente um ganho de desempenho.
fonte