Aqui estão minhas notas de trabalhar com o suporte do MySQL em um problema de bloqueio recente e estranho (versão 5.1.37):
Todas as linhas e entradas de índice percorridas para chegar às linhas que estão sendo alteradas serão bloqueadas. Está coberto em:
http://dev.mysql.com/doc /refman/5.1/en/innodb-locks-set.html
"Uma leitura de bloqueio, um UPDATE ou um DELETE geralmente definem bloqueios de registro em cada registro de índice que é verificado no processamento da instrução SQL. Não importa se existem condições WHERE na instrução que excluiriam a linha. O InnoDB não não se lembra da condição WHERE exata, mas só sabe quais intervalos de índice foram verificados. turn bloqueia todas as inserções de outros usuários na mesa."
Isso é. Uma solução alternativa que geralmente é útil é fazer:
UPDATE qualquer tabela definida para algo onde chave primária (selecione chave primária de qualquer tabela onde as restrições ordenam por chave primária);
A seleção interna não precisa receber bloqueios e a atualização terá menos trabalho a fazer para a atualização. A cláusula order by garante que a atualização seja feita na ordem da chave primária para corresponder à ordem física do InnoDB, a maneira mais rápida de fazê-lo.
Onde um grande número de linhas está envolvido, como no seu caso, pode ser melhor armazenar o resultado da seleção em uma tabela temporária com uma coluna de sinalização adicionada. Em seguida, selecione na tabela temporária onde o sinalizador não está definido para obter cada lote. Execute atualizações com um limite de, digamos, 1000 ou 10000 e defina o sinalizador para o lote após a atualização. Os limites manterão a quantidade de bloqueio em um nível tolerável, enquanto o trabalho selecionado terá que ser feito apenas uma vez. Confirme após cada lote para liberar os bloqueios.
Você também pode acelerar esse trabalho fazendo uma soma selecionada de uma coluna não indexada antes de fazer cada lote de atualizações. Isso carregará as páginas de dados no pool de buffers sem receber bloqueios. Em seguida, o bloqueio durará um período de tempo menor porque não haverá nenhuma leitura de disco.
Isso nem sempre é prático, mas quando é, pode ser muito útil. Se você não puder fazer isso em lotes, você pode pelo menos tentar selecionar primeiro para pré-carregar os dados, se for pequeno o suficiente para caber no buffer pool.
Se possível, use o modo de isolamento de transação READ COMMITTED. Ver:
http://dev.mysql.com/doc/refman /5.1/en/set-transaction.html
Para obter esse bloqueio reduzido, é necessário o uso de log binário baseado em linha (em vez do log binário baseado em instrução padrão).
Dois problemas conhecidos:
-
Às vezes, as subconsultas podem ser menos otimizadas do que o ideal. Nesse caso, era uma subconsulta dependente indesejável - a sugestão que fiz para usar uma subconsulta acabou sendo inútil em comparação com a alternativa neste caso por causa disso.
-
Exclusões e atualizações não têm o mesmo intervalo de planos de consulta que instruções select, portanto, às vezes, é difícil otimizá-las adequadamente sem medir os resultados para descobrir exatamente o que estão fazendo.
Ambos estão melhorando gradualmente. Este bug é um exemplo em que acabamos de melhorar as otimizações disponíveis para uma atualização, embora as alterações sejam significativas e ainda esteja passando pelo controle de qualidade para garantir que não tenha grandes efeitos adversos:
http://bugs.mysql.com/bug.php?id=36569