Onde o InnoDB armazena os dados da transação antes de enviá-los?

12

Eu fiz alguns testes usando READ_COMMITTEDe READ_UNCOMMITTEDem casa, usando a tecnologia JDBC.

Vejo que, READ_UNCOMMITTEDna verdade, é possível ler dados não confirmados, por exemplo, dados de alguma transação ainda não confirmada (poderia executar uma consulta UPDATE).

Questões

  • Onde os dados não confirmados são armazenados, para que uma READ_UNCOMMITTEDtransação possa ler dados não confirmados de outra transação?
  • Por que não é possível para uma READ_COMMITTEDtransação ler dados não confirmados, ou seja, executar uma "leitura suja"? Que mecanismo impõe essa restrição?
Shuzheng
fonte

Respostas:

11

" Onde os dados não confirmados são armazenados, para que uma transação READ_UNCOMMITTED possa ler dados não confirmados de outra transação? "

As novas versões de registro não confirmado (PK em cluster) são tratadas como a versão "atual" do registro na página. Portanto, eles podem ser armazenados no buffer pool e / ou no espaço de tabela (por exemplo, tablename.ibd). As transações que precisam construir uma captura instantânea / exibição em algo diferente de READ-UNCOMMITTED, precisam construir uma versão anterior da linha (seguindo a lista do histórico) usando os registros UNDO (armazenados no espaço de tabela do sistema ). Ao ler o registro não confirmado, o InnoDB também pode precisar ler alguns registros de índice secundário não confirmados do Change Buffer e aplicá-los antes de apresentar o registro novamente ao usuário.

É esse comportamento que pode tornar as reversões no InnoDB relativamente caras. É o grande fator que também pode levar a possíveis problemas de desempenho de transações ociosas de longa duração que mantêm registros atualizados, pois essas transações bloquearão as operações de limpeza e a lista de históricos de versões antigas de registros aumenta, e os registros UNDO necessários para reconstruir essas versões antigas sob demanda, continuará a crescer. Isso diminui a velocidade de novas transações que precisam ler uma versão mais antiga / confirmada do registro, pois elas precisam percorrer uma lista de histórico cada vez mais longa - que é uma lista de registros UNDO com vínculo único - e fazem mais trabalho para reconstruir a versão antiga do registro. Então você acaba usando muitos ciclos de CPU (para não mencionar as primitivas de bloqueio interno: mutexes, rw_locks, semáforos etc.)

Espero que isso faça sentido? :)

Como FYI, no MySQL 5.7, você pode mover o espaço de tabela UNDO e sair do espaço de tabela do sistema , e tê-los truncados automaticamente. Eles podem crescer bastante se você tiver uma transação de longa duração que impeça as operações de limpeza, resultando em um comprimento de lista de histórico muito longo e crescente. Armazená-los no espaço de tabela do sistema foi a causa mais comum de um arquivo ibdata1 enorme / crescente, que por sua vez não pode ser truncado / reduzido / aspirado para recuperar posteriormente esse espaço.

Matt Lord
fonte
4

Você perguntou

onde os dados não confirmados são armazenados, para que uma transação READ_UNCOMMITTED possa ler dados não confirmados de outra transação?

Para responder sua pergunta, você precisa saber como é a arquitetura do InnoDB.

A imagem a seguir foi criada anos atrás por Percona CTO Vadim Tkachenko

Arquitetura InnoDB

De acordo com a documentação do MySQL sobre o modelo de transação e bloqueio do InnoDB

Um COMMIT significa que as alterações feitas na transação atual são permanentes e se tornam visíveis para outras sessões. Uma instrução ROLLBACK, por outro lado, cancela todas as modificações feitas pela transação atual. COMMIT e ROLLBACK liberam todos os bloqueios InnoDB que foram definidos durante a transação atual.

Como COMMIT e ROLLBACK governam a visibilidade dos dados, READ COMMITTED e READ UNCOMMITTED precisariam confiar em estruturas e mecanismos que registram alterações

  1. Segmentos de reversão / espaço de desfazer
  2. Refazer Logs
  3. Lacunas Travas na (s) mesa (s) envolvidas

Os segmentos de reversão e o espaço de desfazer saberiam como eram os dados alterados antes de as alterações serem aplicadas. Refazer registros saberia quais alterações devem ser encaminhadas para que os dados apareçam atualizados.

Você também perguntou

por que não é possível para uma transação READ_COMMITTED ler dados não confirmados, ou seja, executar uma "leitura suja"? Que mecanismo impõe essa restrição?

Refazer logs, desfazer espaço e linhas bloqueadas são ativados. Você também deve considerar o Buffer Pool do InnoDB (onde é possível medir páginas sujas com innodb_max_dirty_pages_pct , innodb_buffer_pool_pages_dirty e innodb_buffer_pool_bytes_dirty ).

À luz disso, READ COMMITTED saberia como os dados aparecem permanentemente. Portanto, não há necessidade de procurar páginas sujas que não foram confirmadas. LEIA COMPROMISSO seria nada mais do que uma leitura suja que foi confirmada. READ UNCOMMITTED continuaria sabendo quais linhas devem ser bloqueadas e quais logs de refazer foram lidos ou ignorados para tornar os dados visíveis.

Para entender completamente o bloqueio de linhas para gerenciar o isolamento, leia O modelo de transação e bloqueio do InnoDB

RolandoMySQLDBA
fonte
1
Primeiro, obrigado pela resposta e modificação do meu post ... Então, antes de um COMMIT, as alterações não são visíveis para outros usuários do sistema? Aqui usuário significa literalmente uma transação, certo? Como READ UNCOMMITTED pode ler dados não confirmados, onde esse nível de isolamento lê esses dados? Poderia haver mais de uma fonte de dados não confirmados para um item de dados específico em um banco de dados? Em caso afirmativo, que dados não confirmados serão lidos?
Shuzheng