2 milhões de linhas inseridas usando LOAD DATA INFILE para innodb levam 7,5 minutos, e a criação de perfil mostra que 99% desse tempo está em "Bloqueio do sistema" .
Isso me diz algo útil?
mysql> set profiling=1;
Query OK, 0 rows affected (0.00 sec)
mysql> LOAD DATA CONCURRENT LOCAL INFILE '/tmp/item' REPLACE INTO TABLE item_load;
Query OK, 1964807 rows affected, 8 warnings (7 min 27.35 sec)
Records: 1964806 Deleted: 1 Skipped: 0 Warnings: 8
mysql> show profile for query 1;
+------------------------------+------------+
| Status | Duration |
+------------------------------+------------+
| starting | 0.000206 |
| checking permissions | 0.000015 |
| Opening tables | 0.000034 |
| System lock | 447.327523 |
| Waiting for query cache lock | 0.000352 |
| query end | 0.000011 |
| closing tables | 0.000014 |
| freeing items | 0.000033 |
| logging slow query | 0.000007 |
| logging slow query | 0.000006 |
| cleaning up | 0.000006 |
+------------------------------+------------+
11 rows in set (0.02 sec)
A função mysql_load() chama a função open_and_lock_tables() para bloquear a tabela mencionada na instrução LOAD DATA.
O MySQL obtém um bloqueio exclusivo na tabela para que possa carregar dados muito rapidamente na tabela. Há muito pouca sobrecarga no processo LOAD DATA, apenas o mínimo de análise é feito para fazê-lo funcionar.
A opção CONCURRENT afeta apenas tabelas MyISAM, se você estiver carregando em uma tabela InnoDB ela não permite acesso concorrente.
A razão pela qual o bloqueio do sistema demorou tanto é que a carga de dados real foi agrupada no tempo para essa etapa. O profiler funciona medindo o tempo entre os fenceposts , ou seja, o tempo de entrada é registrado para cada função de usuário instrumentada. A função mysql_lock_tables() é chamada de dentro de mysql_load(), mas mysql_load() não é instrumentado, então o tempo decorrido começa no bloqueio do sistema e termina no próximo poste da cerca, que foi o bloqueio do cache de consulta.
Seu carregamento de dados de 1,96 milhão de linhas levou cerca de 447 segundos, não há como separar a sobrecarga real do tempo de bloqueio do tempo de carregamento porque o carregamento não é instrumentado.
De acordo com a documentação do MySQL sobre estados gerais de thread
Isso não deve ser surpreendente, pois o InnoDB faz bloqueio em nível de linha. Além disso, o gen_clust_index (também conhecido como Clustered Index) experimentará bloqueios compartilhados e exclusivos na chave primária em algum momento.