Fale sobre o processo de flashing do MySQL e os dados da tabela

Vamos examinar o primeiro problema primeiro, a instrução SQL fica mais lenta

Análise de causa

Uma instrução SQL é muito rápida quando executada normalmente, mas às vezes se torna muito lenta se você não sabe o que está acontecendo, e tal cena é difícil de reproduzir. Ela não é apenas aleatória, mas também tem uma curta duração, como tremer Por um momento.

Nossa instrução de atualização usual apenas executa a ação de gravação em disco de atualizar a página de dados da memória e gravar o log de redo, mas as páginas sujas na memória devem ser atualizadas no disco, ou seja, a ação de descarga. Essa liberação afetará a operação da instrução SQL.

Resuma a cena que desencadeia o flush:

  1.  O log de redo do InnoDB está cheio . Nesse momento, o sistema interromperá todas as operações de atualização, avançará o ponto de verificação e deixará espaço para o log de redo continuar a gravar. Para avançar a posição do ponto de verificação, é necessário descarregar o log entre os dois pontos e todas as páginas sujas correspondentes no disco . Depois disso, da posição de gravação para o ponto de verificação é a área do log de redo que pode ser gravada novamente. O vez que isso acontece, todo o sistema pode não aceitar atualizações, todas as atualizações devem ser bloqueadas. Se você observar a partir do monitoramento, o número de atualizações cairá para 0 neste momento.
  2. A memória do sistema é insuficiente. Quando novas páginas de memória são necessárias e a memória não é suficiente, algumas páginas de dados devem ser eliminadas e a memória é liberada para outras páginas de dados. Se as "páginas sujas" forem eliminadas, primeiro as páginas sujas devem ser gravadas no disco. InnoDB usa um pool de buffer para gerenciar a memória.As páginas de memória no pool de buffer têm três estados: páginas não utilizadas, usadas e limpas e páginas usadas e sujas. A estratégia do InnoDB é usar a memória o máximo possível, portanto, para uma biblioteca de longa execução, há poucas páginas não utilizadas. Quando a página de dados a ser lida não está na memória, uma página de dados deve ser aplicada no buffer pool. Neste momento, apenas a página de dados menos usada pode ser eliminada da memória : se uma página limpa deve ser eliminada, ela é liberada diretamente para reutilização; mas se for uma página suja, a página suja deve ser liberada para o disco primeiro, pode ser reutilizado depois de se tornar uma página em branco.
  3.  Quando o MySQL pensa que o sistema está "ocioso", ele libera algumas "páginas sujas".
  4. Se o MySQL for encerrado normalmente. O MySQL irá liberar todas as páginas sujas da memória para o disco, de forma que na próxima vez que o MySQL for iniciado, os dados possam ser lidos diretamente do disco e a velocidade de inicialização seja muito rápida.

Portanto, embora a liberação de página suja seja normal, as duas situações a seguir afetarão significativamente o desempenho:

  • Existem muitas páginas sujas a serem eliminadas em uma consulta, o que fará com que o tempo de resposta da consulta seja significativamente maior;
  • O log está cheio, todas as atualizações são bloqueadas e o desempenho de gravação cai para 0. Essa situação é inaceitável para empresas confidenciais.

InnoDB esvaziando estratégia de controle de páginas sujas

 O parâmetro innodb_io_capacity informa ao InnoDB a capacidade do disco.Eu sugiro que você defina este valor para o IOPS do disco. O IOPS do disco pode ser testado com a ferramenta fio:

fio -filename=$filename -direct=1 -iodepth 1 -thread -rw=randrw -ioengine=psync -bs=16k -size=500M -numjobs=10 -runtime=10 -group_reporting -name=mytest 

Se o parâmetro innodb_io_capacity não estiver definido corretamente, se a configuração for muito pequena, o InnoDB pensa que a capacidade do sistema é tão fraca, então a liberação de páginas sujas é particularmente lenta, ainda mais lenta do que a geração de páginas sujas, o que causa o acúmulo de páginas sujas, afetando o desempenho da consulta e atualização. Mostra que a velocidade de gravação do MySQL é muito lenta, o TPS é muito baixo, mas a pressão de E / S do host do banco de dados não é grande.

No entanto, esse parâmetro indica apenas a capacidade de liberar páginas sujas, mas também precisa atender às solicitações do usuário. A velocidade de flash do InnoDB é baseada nestes dois fatores: um é a proporção de páginas sujas e o outro é a velocidade de gravação do log de redo . O InnoDB calculará primeiro dois números separadamente com base nesses dois fatores.

  1. O parâmetro innodb_max_dirty_pages_pct é o limite superior da proporção de páginas sujas e o valor padrão é 75%. O InnoDB irá calcular um número que varia de 0 a 100 com base na proporção da página suja atual (assumindo M). O pseudo código para calcular este número é semelhante a este
    F1(M)
    {
      if M>=innodb_max_dirty_pages_pct then
          return 100;
      return 100*M/innodb_max_dirty_pages_pct;
    }
  2. Cada registro escrito pelo InnoDB possui um número de série. A diferença entre o número de série atualmente escrito e o número de série correspondente ao ponto de verificação é considerada como N. O InnoDB calculará um número variando de 0 a 100 com base neste N. Esta fórmula de cálculo pode ser escrita como F2 (N). O algoritmo F2 (N) é mais complicado, contanto que você saiba que quanto maior é N, maior é o valor calculado.
  3. Finalmente, de acordo com os dois valores de F1 (M) e F2 (N) calculados acima, tome o maior valor como R. Então o motor pode multiplicar a capacidade definida por innodb_io_capacity por R% para controlar a velocidade de esvaziamento de páginas sujas .

Agora você sabe que o InnoDB libera páginas sujas em segundo plano, e o processo de esvaziar páginas sujas é gravar páginas de memória no disco. Portanto, se sua instrução de consulta pode exigir que uma página suja seja eliminada quando a memória é necessária, ou devido à lógica de liberar páginas sujas, ela ocupará recursos de IO e pode afetar sua instrução de atualização, o que pode fazer com que você perceba da empresa lado O motivo da "agitação" para o MySQL. Em outras palavras, geralmente preste mais atenção à proporção de páginas sujas e não deixe que ela se aproxime de 75%. A proporção de páginas sujas é obtida por meio de Innodb_buffer_pool_pages_dirty / Innodb_buffer_pool_pages_total . Para comandos específicos, consulte o seguinte código:

mysql> select VARIABLE_VALUE into @a from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty';
select VARIABLE_VALUE into @b from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total';
select @a/@b;

No entanto, outro mecanismo no MySQL pode tornar sua consulta mais lenta: ao preparar para liberar uma página suja, se a página de dados próxima à página de dados for uma página suja, esse "vizinho" também será levado com você. Flush junto; e para cada página de dados vizinha, se a página de dados adjacente ainda estiver suja, ela também será limpa.

No InnoDB, o parâmetro innodb_flush_neighbors é usado para controlar este comportamento. Quando o valor for 1, haverá o mecanismo de "sessão contínua" mencionado acima, e quando o valor for 0, significa que você não encontra vizinhos e se escova . Essa otimização é muito significativa na era dos discos rígidos mecânicos e pode reduzir muito IO aleatório . O IOPS aleatório de um disco rígido mecânico geralmente é de apenas algumas centenas.A redução do IO aleatório com a mesma operação lógica significa que o desempenho do sistema é muito melhorado.

Se você estiver usando um dispositivo com IOPS alto, como SSD, sugiro que defina o valor de innodb_flush_neighbors como 0. Como o IOPS geralmente não é o gargalo no momento, "apenas se liberar" pode executar as operações de liberação necessárias mais rapidamente e reduzir o tempo de resposta das instruções SQL.

Além do controle de velocidade de página suja mencionado acima, o log de redo não pode ser definido muito pequeno . O log de redo deve ser gravado toda vez que uma transação for enviada. Se a configuração for muito pequena, ela será preenchida em breve e a posição de gravação está perseguindo o CP. Nesse momento, o sistema deve interromper todas as atualizações e avançar o ponto de verificação. Então, o que você vê é que a pressão do disco é muito pequena, mas o desempenho do banco de dados cai intermitentemente .

A seguir, vejamos a segunda pergunta. Se metade dos dados da tabela for excluída, o tamanho do arquivo da tabela permanece o mesmo.

analise de problemas

Uma tabela InnoDB contém duas partes, a saber: definição da estrutura da tabela e dados. Antes do MySQL 8.0, a estrutura da tabela era armazenada em um arquivo com o sufixo .frm . A versão do MySQL 8.0 permitiu que a definição da estrutura da tabela fosse colocada na tabela de dados do sistema .

O parâmetro innodb_file_per_table pode controlar se os dados da tabela são armazenados no espaço de tabela compartilhado ou em um arquivo separado:

  • OFF significa que os dados da tabela são colocados no espaço de tabelas compartilhado do sistema, ou seja, junto com o dicionário de dados;
  •  ON significa que cada dado da tabela InnoDB é armazenado em um arquivo com um sufixo .ibd.

A partir da versão 5.6.6 do MySQL, seu valor padrão é ON. É mais fácil gerenciar essa tabela separadamente como um arquivo e, quando você não precisar da tabela, o sistema excluirá o arquivo diretamente por meio do comando drop table. Se for colocado em um espaço de tabela compartilhado, mesmo se a tabela for excluída, o espaço não será recuperado.

Ao excluir a tabela inteira, você pode usar o comando drop table para recuperar o espaço de tabela . No entanto, o cenário de exclusão de mais dados que encontramos é para excluir certas linhas.Neste momento, encontramos o problema no início de nosso artigo: os dados na tabela foram excluídos, mas o espaço de tabela não foi recuperado.

Processo de exclusão de dados

Sabemos que os dados no InnoDB são organizados em uma estrutura de árvore B + . Queremos deletar um registro, o motor InnoDB irá apenas marcar este registro como deletado , se você quiser inserir um registro mais tarde, ele pode reutilizar esta posição. No entanto, o tamanho do arquivo do disco não será reduzido .

Portanto, se excluirmos todos os registros de uma página de dados, toda a página de dados poderá ser reutilizada . No entanto, a multiplexação de páginas de dados é diferente da multiplexação de registros, pois a multiplexação de registros é limitada aos dados que atendem às condições de intervalo, e quando a página inteira é removida da árvore B +, ela pode ser reutilizada em qualquer posição .

Se a utilização de duas páginas de dados adjacentes for muito baixa, o sistema mesclará os dados dessas duas páginas em uma das páginas e a outra página de dados será marcada como reutilizável. Além disso, e se excluirmos os dados de toda a tabela com o comando delete? O resultado é que todas as páginas de dados serão marcadas como reutilizáveis. Mas no disco, o arquivo não ficará menor. Em outras palavras, o espaço de tabela não pode ser recuperado por meio do comando delete . Eles podem ser reutilizados, mas o espaço não utilizado parece "buracos".

Na verdade, não apenas a exclusão de dados criará lacunas, mas também a inserção de dados.

Se os dados forem inseridos em ordem crescente do índice , o índice será compacto . Mas se os dados forem inseridos aleatoriamente, isso pode causar a divisão da página de dados do índice .

Supondo que uma determinada página de dados de um determinado índice esteja cheia, desejo inserir uma linha de dados no intervalo e devo solicitar uma nova página para salvar os dados. Depois que a divisão da página é concluída, um buraco é deixado no final da página antiga e pode haver mais de um registro com um buraco.

Além disso, atualizar o valor no índice pode ser entendido como a exclusão de um valor antigo e a inserção de um novo valor, o que também causará lacunas. Em outras palavras, as tabelas que sofreram um grande número de adições, exclusões e modificações podem ter buracos. Portanto, se esses buracos puderem ser removidos, o objetivo de reduzir o espaço da mesa pode ser alcançado.

Mesa de reconstrução

Com base na análise do problema acima, resolver o vazio pode atingir o objetivo de reduzir o espaço, basta reconstruir a mesa.

O processo de reconstrução da mesa:

Crie uma nova tabela com a mesma estrutura da tabela original e, em seguida, leia os dados linha por linha da tabela de origem e insira-os na nova tabela na ordem crescente do ID da chave primária. Desta forma, não há buracos no índice da chave primária da tabela antiga na nova tabela. Obviamente, o índice de chave primária da nova tabela é mais compacto e a utilização de páginas de dados também é maior . Se usarmos a nova tabela como uma tabela temporária, após os dados serem importados para a nova tabela, a nova tabela substituirá a tabela antiga.do ponto de vista do efeito, diminuirá o espaço da tabela antiga.

Você pode usar o comando alter table A engine = InnoDB para reconstruir a tabela. Antes do MySQL 5.5 , o processo de execução deste comando era semelhante ao que descrevemos anteriormente. A diferença é que esta tabela temporária não precisa ser criada por você. O MySQL completará automaticamente as operações de despejo de dados, troca de nomes de tabela e exclusão tabelas velhas.

Neste processo, a etapa mais demorada é o processo de inserção de dados na tabela temporária.Se houver novos dados a serem gravados na tabela antiga durante este processo, haverá perda de dados. Portanto, em todo o processo DDL, não pode haver atualizações na tabela antiga, ou seja, este DDL não é Online .

O DDL online introduzido na versão 5.6 do MySQL otimiza este processo de operação.

Após a introdução do DDL online, o processo de reconstrução da mesa:

  1. Crie um arquivo temporário para varrer todas as páginas de dados da chave primária da tabela original;
  2. Use os registros da tabela original na página de dados para gerar uma árvore B + e armazená-la em um arquivo temporário;
  3. No processo de geração de arquivos temporários, registre todas as operações na tabela original em um arquivo de log (log de linha);
  4. Depois que o arquivo temporário for gerado, aplique as operações no arquivo de log ao arquivo temporário para obter um arquivo de dados com os mesmos dados lógicos da tabela original;
  5. Substitua os arquivos de dados na Tabela A por arquivos temporários.

Em circunstâncias normais, o bloqueio de gravação MDL é necessário antes do DDL. A instrução alter precisa adquirir o bloqueio de gravação MDL quando é iniciada , mas esse bloqueio de gravação degenera em um bloqueio de leitura antes que os dados sejam realmente copiados . Por que degenerar? Para realizar o Online, o bloqueio de leitura MDL não bloqueará as operações de adição, exclusão e modificação. Mas não pode ser desbloqueado diretamente, para evitar que outras threads façam DDL nesta tabela ao mesmo tempo.

Para uma tabela grande, o processo mais demorado do DDL online é o processo de cópia dos dados para uma tabela temporária. Adições, exclusões e modificações podem ser aceitas durante a execução desta etapa. Portanto, em relação a todo o processo DDL, o tempo de bloqueio é muito curto. Para negócios, pode ser considerado Online.

É preciso acrescentar que os métodos de reconstrução acima irão varrer os dados da tabela original e construir arquivos temporários . Para tabelas muito grandes, essa operação consome recursos de E / S e CPU . Portanto, se for um serviço online, você deve controlar cuidadosamente o tempo de operação. Se você quiser uma operação mais segura, recomendo usar o gh-ost de código aberto do GitHub.

Online 和 no local

Falando em Online, precisamos esclarecer a diferença entre ele e outro conceito confuso relacionado ao DDL.

Como mencionado acima, antes da versão 5.5, reconstruir tabelas é inserir dados em tabelas temporárias, e após a versão 5.6, é colocar dados em arquivos temporários.A primeira é feita na camada do servidor, e a última é feita no motor InnoDB camada criança.

Então, para a camada do servidor, é uma operação "local" que não move os dados para a tabela temporária.Esta é a origem do nome "local", mas os arquivos temporários também ocupam espaço temporário.

A instrução de que reconstruímos a tabela alter table t engine = InnoDB na verdade implica que alter table t engine = innodb, ALGORITHM = inplace;

Correspondente a inplace é a maneira de copiar a tabela, alter table t engine = innodb, ALGORITHM = copy;

Quando ALGORITHM = copy é usado, significa que a tabela é forçada a ser copiada, e o processo correspondente é o processo de operação da tabela temporária.

Até este ponto, à primeira vista, inplace também está online, mas na verdade, aqui está apenas porque a lógica de reconstrução da tabela está no local e também pode ser operações DML.

Por exemplo, eu quero adicionar um índice de texto completo a um campo de uma tabela InnoDB, escrito como: alter table t add FULLTEXT (field_name); este processo está em vigor, mas irá bloquear as operações de adição, exclusão e modificação, e não é online.

A relação entre essas duas lógicas pode ser resumida como:

  • Se o processo DDL estiver online, ele deve estar instalado;
  • O inverso não é necessariamente verdadeiro, ou seja, o DDL do inplace pode não ser Online. No MySQL 8.0, esse é o caso com a adição do índice de texto completo (índice FULLTEXT) e índice espacial (índice ESPACIAL).

Para estender, otimizar a tabela, analisar a tabela e alterar a tabela são as três maneiras de reconstruir a diferença entre a tabela:

  • A partir da versão 5.6 do MySQL, altere a tabela t engine = InnoDB (isto é, recriar) padrões para o processo de armazenamento de dados nos arquivos temporários acima;
  • analisar a tabela t não está realmente reconstruindo a tabela, mas reafirmando as informações de índice da tabela sem modificar os dados. O bloqueio de leitura de MDL é adicionado neste processo;
  • otimizar tabela t é igual a recriar + analisar.

Em relação à reconstrução da tabela, existe um problema extremo:

Às vezes, usar alter table t engine = InnoDB aumentará o espaço ocupado por uma mesa.

Motivo: Ao reconstruir a tabela, o InnoDB não preencherá a tabela inteira, e 1/16 de cada página é reservado para atualizações subsequentes. Em outras palavras, não é o "mais" compacto após a reconstrução da mesa. Se houver uma nova operação DML antes de reconstruir novamente, ela ocupará o espaço restante da página. Neste momento, se você encolher novamente, continuará a reservar espaço em 1/16, de modo que, após encolher, o arquivo ficará maior.

Fonte do conteúdo: Lin Xiaobin "45 Lectures on MySQL Actual Combat"

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Acho que você gosta

Origin blog.csdn.net/qq_24436765/article/details/112557501
Recomendado
Clasificación