maneira de impedir que as consultas aguardem pelo bloqueio no nível da tabela

10

Encontramos um problema depois de mover o banco de dados de nosso cliente para um servidor extra. Isso deveria ter tido efeitos positivos no desempenho do site, mas há um problema com o bloqueio de tabelas no MyISAM. (Eu ouvi falar do uso do InnoDB em vez do MyISAM, mas não podemos mudar o mecanismo em um futuro próximo).
Poderíamos identificá-lo para uma consulta de atualização que é executada quando um moderador ativa um comentário no site de artigos. Este é o processo:

  • a consulta de atualização é processada SET status = 1 WHERE id = 5(o índice está definido)
  • os arquivos em cache da página são excluídos

Nesse ponto, a página inteira fica lenta. O próprio banco de dados está ocupado por minutos. Busquei a lista de processos algumas vezes e vi cerca de 60 entradas de diferentes consultas de seleção, que estavam todas no estado aguardando o bloqueio no nível da tabela .

1. Não entendo por que essa atualização na tabela article_commentspode afetar as instruções de seleção da tabela articlepara aguardar o bloqueio no nível da tabela. Na lista de processos, quase todas as consultas em espera eram desta tabela. Eu li sobre o fato de que as atualizações / inserções são preferíveis às seleções e que isso pode causar esses problemas, mas a tabela de artigos em si não é atualizada quando os comentários são ativados, portanto as seleções não devem esperar. Eu não sabia disso?
2. Existe algo além de mudar para o InnoDB para evitar esse comportamento ou pelo menos para obter um melhor equilíbrio? Estou muito irritado com o fato de que esse problema não apareceu antes de mover o banco de dados para o novo servidor. Acho que há alguma configuração incorreta, mas não sei como identificar.

32bitfloat
fonte
11
Ative o log geral e observe as instruções JOIN entre essas tabelas. Quando você seleciona, ele cria um READ LOCK implícito. Como o MYISAM não suporta o bloqueio ROW LEVEL, ele bloqueia no nível da mesa. Provavelmente, esse bloqueio estava acontecendo no servidor antigo, mas ninguém estava assistindo? Compare sua linha my.cnf para a linha entre hosts e verifique se o seu key_buffer está ajustado corretamente.
randomx 18/07/12
Tivemos vários outros problemas de desempenho no servidor antigo e assistimos frequentemente à lista de processos. Havia principalmente muitos processos adormecidos, mas nunca notamos processos em espera (eu vi essas informações geralmente pela primeira vez neste novo servidor). Meu colega copiou o antigo my.cnf e ajustou os valores ao novo hardware existente, mas não havia muitas entradas. Também comparei os resultados de "SHOW VARIABLES", mas não sabia realmente o que procurar. Amanhã vamos verificar novamente o buffer de teclas, obrigado pelo seu comentário.
32bitfloat
Recentemente, tivemos um problema semelhante. Inicialmente nosso key_buffer_sizefoi definido como 1GB. Aumentar isso para 10GBreduzir o problema.
Haluk
@ Rick James, obrigado. Você me salvou muitos problemas hoje. Você tem uma lista de desejos na Amazon ou em outro lugar? :) Configurei o query_cache_limit para 1024. Não há problema de bloqueio agora. Eu fiz isso em variáveis ​​no início do cliente mysql. defina global query_cache_limit = 1024; Agora vou escrever no my.cnf. Essa solução me deu tempo para planejar a migração do innodb sem nenhum esforço, então obrigado.

Respostas:

8

O MyISAM Storage Engine é furiosamente notório por executar bloqueios de tabela completos para qualquer DML (INSERTs, UPDATEs, DELETEs). O InnoDB definitivamente resolveria esse problema a longo prazo.

Escrevi sobre prós e contras do uso do MyISAM vs InnoDB

Com relação à sua pergunta atual, aqui está um cenário possível:

  • articlee article_commentssão ambas tabelas MyISAM
  • article_commentspossui um ou mais índices com statusuma coluna
  • As atualizações da página de índice para article_commentssão armazenadas em cache no MyISAM Key Buffer (dimensionado por key_buffer_size ), fazendo com que páginas de índice antigas saiam do MyISAM Key Buffer
  • Você tem consultas SELECT que executam JOINs entre articleearticle_comments

No meu cenário sugerido, os SELECTs contra a articletabela podem ser impedidos de permitir gravações, pois precisam aguardar article_commentsa liberação de qualquer DML (nesse caso, um UPDATE)

RolandoMySQLDBA
fonte
Obrigado pela sua resposta (e pelos links), seu cenário é real. Não percebi que a maioria dos artigos selecionados realmente se juntou à tabela de comentários (ou, em outras palavras, vi as declarações incompletas na lista de processos do phpmyadmin). Você conhece uma solução de curto prazo para evitar as várias consultas em espera? Eu já tentei com "UPDATE LOW_PRIORITY" na declaração específica, mas isso não fez alterações visíveis. Nós realmente mudaremos para innodb no futuro, mas me pergunto se existe uma maneira de obter uma melhoria atualmente.
32bitfloat
Solução definitiva: converta tabelas para o InnoDB. Veja meu post dba.stackexchange.com/a/9422/877 sobre como converter tudo MyISAM para InnoDB
RolandoMySQLDBA
7

Nesse ponto, a página inteira fica lenta. O próprio banco de dados está ocupado por minutos.

Cheira como você tem um grande Query_cache?

mysql> SHOW VARIABLES LIKE 'query_cache%';
+------------------------------+----------+
| Variable_name                | Value    |
+------------------------------+----------+
| query_cache_limit            | 1048576  |
| query_cache_min_res_unit     | 4096     |
| query_cache_size             | 16777216 | -- Not over 50M
| query_cache_type             | DEMAND   | -- Only if using SQL_CACHE
| query_cache_wlock_invalidate | OFF      |
+------------------------------+----------+

Para sistemas de produção com muitas gravações, você também pode desativar o query_cache.

Todas as entradas no query_cache para a tabela especificada são eliminadas quando qualquer gravação ocorre nessa tabela. Quanto maior o CQ, mais lenta é essa tarefa.

O MyISAM usa bloqueios "no nível da tabela". Leituras e gravações não podem ocorrer ao mesmo tempo (na mesma tabela). Bruto, mas eficaz.

Rick James
fonte
11
Bem, sim. Temos cerca de 64 milhões de cache. Obrigado por essa informação que era nova para mim, no entanto, tínhamos o mesmo valor no servidor antigo, onde não percebemos os travamentos de mesa. Nós já começaram a se mover para InnoDB mas este fato permanece como um mistério ...
32bitfloat