MySQL LOAD DATA INFILE diminui em 80% após alguns shows de entrada com o mecanismo InnoDB

14

Estou carregando um arquivo de 100 GB via LOAD DATA INFILE. Eu tive um bom sucesso com o MyISAM, algumas horas e pronto.

Estou tentando agora usando o InnoDB. O carregamento começa rapidamente em mais de 10 MB / s (observando o crescimento do arquivo da tabela, file_per_tableestá ativado).

Mas, após cerca de 5 GB de dados, ele diminui para o intervalo de 2-4 MB / s, enquanto eu tenho mais de 20 GB, ele cai em torno de 2 MB / s.

O tamanho do buffer pool do InnoDB é 8G. E eu fiz o seguinte antes de executar o 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....

Não vejo a razão pela qual está começando bem e diminuindo com o tempo.

Além disso, usando as mesmas configurações, executei o mesmo comando LOAD DATA INFILE com a tabela usando o InnoDB e o MyISAM e um conjunto de dados de teste de 5 GB, o MyISAM foi 20x mais rápido:

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

Mais alguma coisa que eu deva considerar tentar? O mecanismo MyISAM é capaz de manter a taxa de carga muito melhor.


Detalhes adicionais:

  • Eu tentei carregar os arquivos individualmente, não há diferença.

  • Aliás, tenho 150 arquivos de 500 MB cada, em cada arquivo as chaves são classificadas.

  • Após receber 40 GB da noite para o dia, 12 horas depois, a taxa de carregamento caiu para 0,5 MB / s, o que significa que a operação é, praticamente falando, impossível.

  • Não encontrei outras respostas para perguntas semelhantes em outros fóruns, parece-me que o InnoDB não suporta o carregamento de grandes quantidades de dados em tabelas com mais de alguns GB de tamanho.

David Parks
fonte

Respostas:

7

OBSERVAÇÃO Nº 1

Notei que você desligou autocommit. Isso acumulará muitos dados no ibdata1. Por quê?

Existem sete (7) classes de informações armazenadas no ibdata1:

  • Páginas de dados para tabelas do InnoDB
  • Páginas de índice para tabelas do InnoDB
  • Dicionário de dados
  • Buffer de gravação dupla
    • Rede de segurança para impedir a corrupção de dados
    • Ajuda a ignorar o SO para cache
  • Inserir buffer (simplifica as alterações nos índices secundários)
  • Segmentos de reversão
  • Desfazer logs
  • Clique aqui para ver uma representação pictórica de ibdata1

Algumas dessas informações ficam visíveis para certas transações, dependendo do nível de isolamento. Tais ações podem produzir bloqueios de chave primária não intencionais e muitos dados fantasmas . À medida que essas duas coisas aumentam, você deve esperar uma desaceleração justa.

Recomendação: deixe a confirmação automática ativada

OBSERVAÇÃO Nº 2

Vejo que você tem isso:

alter table item_load disable keys;

DISABLE KEYS não funciona com o InnoDB . Aqui está o porquê:

  • MyISAM: DISABLE KEYSsimplesmente desliga a atualização do Índice Secundário para a tabela MyISAM. Quando você insere em massa INSERT em uma tabela MyISAM com as teclas desativadas, resulta em um carregamento rápido da tabela, juntamente com a criação da PRIMARY KEY e de todos os índices exclusivos. Quando você executa ENABLE KEYS, todos os índices secundários são criados linearmente na tabela e anexados ao .MYD.
  • InnoDB: Como mostrado na imagem interna do InnoDB, a tabela de sistema ibdata1tem uma estrutura dedicada às inserções de índice secundário. No momento, não há nenhuma provisão para lidar com índices da mesma forma que o MyISAM.

Para ilustrar isso, observe minha tentativa de executar DISABLE KEYS em uma tabela InnoDB no 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>

OBSERVAÇÃO Nº 3

Você notou que o MyISAM carrega 20 vezes mais rápido que o InnoDB. Deseja que isso seja mais 24-25 vezes mais rápido? Em seguida, execute o seguinte:

ALTER TABLE item_load ROW_FORMAT=Fixed;

Isso acelerará o tempo de INSERTs de 20 a 25% sem outras alterações de DDL . Efeito colateral: a tabela MyISAM pode crescer de 80% a 100%, possivelmente maior.

Você também pode executar isso em uma tabela do InnoDB, mas o comportamento compatível com ACID e o MVCC do InnoDB ainda seriam o gargalo de seu desempenho, especialmente se os campos VARCHAR aumentarem significativamente forem gravados ibdata1.

RolandoMySQLDBA
fonte
As duas primeiras observações foram coisas que tentei adicionar para corrigir o problema depois que o notei. Minha primeira tentativa foi naturalmente deixar o innodb em paz (basta desativar o log de lixeira). Na terceira observação, o tamanho dos meus dados é altamente variável em comprimento, presumo que isso seja um problema? Estou sentindo que só preciso manter essa tabela myisam.
David Parks
6

A resposta final para esta pergunta foi não usar o InnoDB para uma tabela de referência massiva. O MyISAM está gritando rápido, quase com a taxa de transferência máxima da velocidade do disco para toda a carga, o InnoDB atola. MyISAM é simples, mas neste caso também são os requisitos desta tabela. Para uma tabela de referência simples com cargas em massa sobre LOAD DATA INFILE, o MyISAM é o caminho a percorrer, até agora tudo bem.

Mas observe que, se você executar as tabelas MyISAM e InnoDB, precisará considerar a alocação de memória para 2 mecanismos de armazenamento em cache, cada mecanismo possui seu próprio cache exclusivo, que precisa de alocação de memória separada.

David Parks
fonte
5

Você pode tentar dividir seus arquivos de entrada em pedaços menores.

Eu pessoalmente uso http://www.percona.com/doc/percona-toolkit/2.1/pt-fifo-split.html para isso.

O que acontece se você obtiver um bloqueio de tabela durante a importação? Talvez o bloqueio no nível de linha do InnoDB o retarde (o MyISAM usa um bloqueio de tabela).

Você também pode ler aqui para obter mais ideias: http://derwiki.tumblr.com/post/24490758395/loading-half-a-billion-rows-into-mysql

Bnadland
fonte
Meus arquivos já estão em blocos de 500 MB, eu os estava canalizando através de um único pipe nomeado para facilitar o carregamento, mas tentarei essa abordagem agora.
David Parks
Não vendo nenhuma diferença aqui, rapidamente vejo a velocidade cair de 11 MB / s de expansão do arquivo DB para 6 MB (após cerca de 2 GB) de dados e continua caindo. Estou carregando todos os arquivos em um loop for, chamadas mysql separadas.
David Parks
O primeiro arquivo carregado em 54s, 2º em 3m39s, 3º em 3m9s, 4m7s, 5m21s e assim por diante. todos os arquivos aproximadamente do mesmo tamanho.
David Parks
2

Se o seu PK não for AUTO_INCREMENT ou os dados no arquivo csv não estiverem classificados no PK, isso poderá estar afetando o desempenho do carregamento de dados. Como a tabela no MySQL é um índice, portanto, todos os dados são armazenados em ordem classificada, se o valor PK não estiver em AUTO_INCREMENT, o MySQL precisará fazer muita troca de dados para obter os dados armazenados em ordem classificada. Esse é o motivo do carregamento mais lento de dados quando o tamanho da tabela começa a aumentar.

Estou carregando um arquivo csv de 91GB com PK em AUTO_INCREMENT usando LOAD DATA INFILE e não vejo nenhuma queda na taxa de transferência. Estou recebendo inserções de 140 a 145 mil por segundo. Usando o Percona MySQL 5.6.38

KKYadav
fonte