

# Recomendações para recursos do MySQL no Aurora MySQL
<a name="AuroraMySQL.BestPractices.FeatureRecommendations"></a>

Os recursos a seguir estão disponíveis no Aurora MySQL compatíveis com o MySQL. Contudo, eles apresentam problemas de performance, escalabilidade, estabilidade ou compatibilidade no ambiente do Aurora. Assim, recomendamos que você siga determinadas diretrizes no uso desses recursos. Por exemplo, recomendamos não usar determinados recursos para implantações de produção do Aurora.

**Topics**
+ [Utilizar a replicação de vários threads no Aurora MySQL](#AuroraMySQL.BestPractices.MTReplica)
+ [Invocar funções do AWS Lambda com o uso de funções nativas do MySQL](#AuroraMySQL.BestPractices.Lambda)
+ [Como evitar transações XA com o Amazon Aurora MySQL](#AuroraMySQL.BestPractices.XA)
+ [Como manter chaves externas ativadas durante instruções DML](#Aurora.BestPractices.ForeignKeys)
+ [Configurar a frequência com que o buffer de log é liberado](#AuroraMySQL.BestPractices.Flush)
+ [Minimizar e solucionar problemas de deadlocks do Aurora MySQL](#AuroraMySQL.BestPractices.deadlocks)

## Utilizar a replicação de vários threads no Aurora MySQL
<a name="AuroraMySQL.BestPractices.MTReplica"></a>

Com a replicação de logs binários de vários threads, um thread SQL faz a leitura de eventos do log de retransmissão e coloca esses eventos em fila para que os threads de operador SQL sejam aplicados. Os threads de operador SQL são gerenciados por um thread coordenador. Os eventos de log binário são aplicados em paralelo sempre que possível.

A replicação de vários threads não é compatível com o Aurora MySQL versão 3 e o Aurora MySQL versão 2.12.1 e posterior.

Em relação às versões anteriores à 3.04 do Aurora MySQL, o Aurora usa replicação de um único thread por padrão quando um cluster de bancos de dados do Aurora MySQL é usado como uma réplica de leitura para replicação de log binário.

As versões anteriores do Aurora MySQL versão 2 herdaram alguns problemas relacionados à replicação de vários threads do MySQL Community Edition. Para essas versões, recomendamos não usar a replicação de vários threads em ambientes de produção.

Se você usa a replicação de vários threads, recomendamos testá-la completamente.

Para ter mais informações sobre o uso de replicação no Amazon Aurora, consulte [Replicação com o Amazon Aurora](Aurora.Replication.md). Para ter informações sobre a replicação de vários threads no Aurora MySQL, consulte [Replicação de logs binários de vários threads](binlog-optimization.md#binlog-optimization-multithreading). 

## Invocar funções do AWS Lambda com o uso de funções nativas do MySQL
<a name="AuroraMySQL.BestPractices.Lambda"></a>

Recomendamos usar as funções nativas do MySQL `lambda_sync` e `lambda_async` para invocar funções do Lambda.

Se você estiver usando o procedimento `mysql.lambda_async` obsoleto, recomendamos que você faça chamadas do procedimento `mysql.lambda_async` em um procedimento armazenado. Você pode chamar este procedimento armazenado a partir de origens diferentes, como triggers ou código do cliente. Essa abordagem pode ajudar a evitar problemas de incompatibilidade de impedância e facilita para seus programadores de banco de dados invocar funções do Lambda.

Para ter mais informações sobre como invocar funções do Lambda por meio do Amazon Aurora, consulte [Invocar uma função do Lambda a partir de um cluster de banco de dados do Amazon Aurora MySQL](AuroraMySQL.Integrating.Lambda.md).

## Como evitar transações XA com o Amazon Aurora MySQL
<a name="AuroraMySQL.BestPractices.XA"></a>

Recomendamos que você não use transações eXtended Architecture (XA) com o Aurora MySQL, porque elas podem gerar longos tempos de recuperação se a XA estiver no estado `PREPARED`. Se você precisa usar transações XA com o Aurora MySQL, siga estas práticas recomendadas:
+ Não deixe uma transação XA aberta no estado `PREPARED`.
+ Mantenha as transações XA menores o possível.

Para ter mais informações sobre o uso de transações XA com o MySQL, consulte [Transações XA](https://dev.mysql.com/doc/refman/8.0/en/xa.html) na documentação do MySQL.

## Como manter chaves externas ativadas durante instruções DML
<a name="Aurora.BestPractices.ForeignKeys"></a>

Recomendamos que você não execute nenhuma instrução de linguagem de definição de dados (DDL) quando a variável `foreign_key_checks` estiver definida como `0` (desativada).

Se você precisar inserir ou atualizar linhas que exigem uma violação transitória das chaves externas, siga estas etapas:

1. Defina `foreign_key_checks` como `0`.

1. Faça as alterações na sua linguagem de manipulação de dados (DML).

1. Verifique se as alterações realizadas não violam restrições de chaves externas.

1. Defina `foreign_key_checks` como `1` (ativada).

Além disso, siga estas práticas recomendadas adicionais para restrições de chaves externas:
+ Verifique se suas aplicações cliente não definiram a variável `foreign_key_checks` como `0`, como parte da variável `init_connect`.
+ Se a restauração a partir de um backup lógico, como `mysqldump`, apresentar falha ou não for concluída, defina `foreign_key_checks` como `1` antes de iniciar qualquer outra operação na mesma sessão. Um backup lógico define `foreign_key_checks` como `0` ao ser inicializado.

## Configurar a frequência com que o buffer de log é liberado
<a name="AuroraMySQL.BestPractices.Flush"></a>

No MySQL Community Edition, para tornar as transações duráveis, o buffer de log do InnoDB deve ser liberado para um armazenamento durável. Use o parâmetro `innodb_flush_log_at_trx_commit` para configurar a frequência com que o buffer de log é liberado para o disco.

Quando você define o parâmetro `innodb_flush_log_at_trx_commit` como o valor padrão de 1, o buffer de log é liberado em cada confirmação de transação. Essa configuração ajuda a manter o banco de dados compatível com [ACID](https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_acid). Recomendamos que você mantenha a configuração padrão 1.

Alterar `innodb_flush_log_at_trx_commit` para um valor não padrão pode ajudar a reduzir a latência da linguagem de manipulação de dados (DML), mas sacrifica a durabilidade dos registros de log. Essa falta de durabilidade torna o banco de dados incompatível com ACID. Recomendamos que seus bancos de dados estejam em conformidade com ACID para evitar o risco de perda de dados em caso de uma reinicialização do servidor. Para ter mais informações sobre esse parâmetro, consulte [innodb\$1flush\$1log\$1at\$1trx\$1commit](https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit) na documentação do MySQL.

No Aurora MySQL, o processamento de redo log é transferido para a camada de armazenamento, portanto, nenhuma descarga dos arquivos de log ocorre na instância de banco de dados. Quando uma gravação é emitida, os redo logs são enviados da instância de banco de dados do gravador diretamente ao volume do cluster do Aurora. As únicas gravações que atravessam a rede são os registros de redo log. Nenhuma página é gravada na camada do banco de dados.

Por padrão, cada thread que confirma uma transação aguarda a confirmação do volume do cluster do Aurora. Essa confirmação indica que esse registro e todos os registros anteriores de redo log foram gravados e atingiram o [quórum](https://aws.amazon.com/blogs/database/amazon-aurora-under-the-hood-quorum-and-correlated-failure/). A persistência dos registros de log e a obtenção do quórum tornam a transação durável, seja por meio de confirmação automática ou confirmação explícita. Para ter mais informações sobre a arquitetura de armazenamento do Aurora, consulte [Amazon Aurora storage demystified](https://d1.awsstatic.com/events/reinvent/2020/Amazon_Aurora_storage_demystified_DAT401.pdf) (Armazenamento desmistificado do Amazon Aurora).

O Aurora MySQL não libera logs para arquivos de dados como o MySQL Community Edition. No entanto, você pode usar o parâmetro `innodb_flush_log_at_trx_commit` para reduzir as restrições de durabilidade ao gravar registros de redo log no volume do cluster do Aurora.

Para o Aurora MySQL versão 2:
+ `innodb_flush_log_at_trx_commit` = 0 ou 2: o banco de dados não espera pela confirmação de que os registros de log redo sejam gravados no volume do cluster do Aurora.
+ `innodb_flush_log_at_trx_commit` = 1: o banco de dados aguarda a confirmação de que os registros de log redo foram gravados no volume do cluster do Aurora.

Para o Aurora MySQL versão 3:
+ `innodb_flush_log_at_trx_commit` = 0: o banco de dados não espera pela confirmação de que os registros de log redo sejam gravados no volume do cluster do Aurora.
+ `innodb_flush_log_at_trx_commit` = 1 ou 2: o banco de dados aguarda a confirmação de que os registros de log redo foram gravados no volume do cluster do Aurora.

Portanto, para obter o mesmo comportamento não padrão no Aurora MySQL versão 3 que seria obtido com o valor definido como 0 ou 2 no Aurora MySQL versão 2, defina o parâmetro como 0.

Embora essas configurações possam diminuir a latência do DML para o cliente, elas também podem ocasionar perda de dados no caso de failover ou reinicialização. Portanto, recomendamos que você mantenha o parâmetro `innodb_flush_log_at_trx_commit` definido como o valor padrão de 1.

Embora a perda de dados possa ocorrer tanto no MySQL Community Edition quanto no Aurora MySQL, o comportamento difere em cada banco de dados devido às diferentes arquiteturas. Essas diferenças de arquitetura podem ocasionar vários graus de perda de dados. Para garantir que o banco de dados seja compatível com ACID, sempre defina `innodb_flush_log_at_trx_commit` como 1.

**nota**  
No Aurora MySQL versão 3, antes de alterar `innodb_flush_log_at_trx_commit` para um valor diferente de 1, é necessário primeiro alterar o valor de `innodb_trx_commit_allow_data_loss` para 1. Ao fazer isso, você reconhece o risco de perda de dados.

## Minimizar e solucionar problemas de deadlocks do Aurora MySQL
<a name="AuroraMySQL.BestPractices.deadlocks"></a>

Usuários que executam workloads que regularmente enfrentam violações de restrições em índices secundários exclusivos ou chaves estrangeiras, ao modificar registros na mesma página de dados simultaneamente, podem ter maiores deadlocks e tempos de espera de bloqueio. Esses deadlocks e tempos limite são causados por uma [correção de bug](https://bugs.mysql.com/bug.php?id=98324) do MySQL Community Edition.

Essa correção está incluída nas versões 5.7.26 e posteriores do MySQL Community Edition e foi transferida para as versões 2.10.3 e posteriores do Aurora MySQL. A correção é necessária para reforçar a *capacidade de serialização* por meio da implementação de bloqueios adicionais para esses tipos de operação de linguagem de manipulação de dados (DML) nas alterações feitas nos registros em uma tabela do InnoDB. Esse problema foi descoberto como parte de uma investigação sobre problemas de deadlock introduzidos por uma [correção de bug](https://dev.mysql.com/doc/relnotes/mysql/5.7/en/news-5-7-26.html) anterior do MySQL Community Edition.

A correção alterou o tratamento interno da *reversão parcial* de uma atualização de tupla (linha) no mecanismo de armazenamento InnoDB. Operações que geram violações de restrição em chaves estrangeiras ou índices secundários exclusivos causam reversão parcial. Isso inclui, entre outros, as instruções simultâneas `INSERT...ON DUPLICATE KEY UPDATE`, `REPLACE INTO,` e `INSERT IGNORE` (*upserts*).

Nesse contexto, a reversão parcial não se refere à reversão de transações em nível de aplicação, mas sim a uma reversão interna do InnoDB das alterações em um índice em cluster, quando uma violação de restrição é encontrada. Por exemplo, um valor de chave duplicado é encontrado durante uma operação de upsert.

Em uma operação normal de inserção, o InnoDB cria atomicamente entradas de índice secundárias e [em cluster](https://dev.mysql.com/doc/refman/5.7/en/innodb-index-types.html) para cada índice. Se o InnoDB detectar um valor duplicado em um índice secundário exclusivo durante uma operação de upsert, a entrada inserida no índice em cluster deverá ser revertida (reversão parcial) e a atualização deverá ser aplicada à linha duplicada existente. Durante essa etapa interna de reversão parcial, o InnoDB deve bloquear cada registro visto como parte da operação. A correção garante a capacidade de serialização da transação ao introduzir bloqueios adicionais após a reversão parcial.

### Minimizar os deadlocks do InnoDB
<a name="AuroraMySQL.BestPractices.deadlocks-minimize"></a>

Você pode adotar as abordagens a seguir para reduzir a frequência de deadlocks em sua instância de banco de dados. Mais exemplos podem ser encontrados na [documentação do MySQL](https://bugs.mysql.com/bug.php?id=98324).

1. Para reduzir as chances de deadlock, confirme as transações imediatamente depois de fazer um conjunto relacionado de alterações. Você pode fazer isso dividindo transações grandes (atualizações de várias linhas entre confirmações) em transações menores. Se você estiver inserindo linhas em lote, tente reduzir os tamanhos das inserções em lote, especialmente ao usar as operações de upsert mencionadas anteriormente.

   Para reduzir o número de possíveis reversões parciais, você pode tentar algumas das seguintes abordagens:

   1. Substitua as operações de inserção em lote pela inserção de uma linha por vez. Isso pode reduzir o tempo em que os bloqueios são mantidos por transações que podem ter conflitos.

   1. Em vez de usar `REPLACE INTO`, reescreva a instrução SQL como uma transação com várias instruções, como a seguinte:

      ```
      BEGIN;
      DELETE conflicting rows;
      INSERT new rows;
      COMMIT;
      ```

   1. Em vez de usar `INSERT...ON DUPLICATE KEY UPDATE`, reescreva a instrução SQL como uma transação com várias instruções, como a seguinte:

      ```
      BEGIN;
      SELECT rows that conflict on secondary indexes;
      UPDATE conflicting rows;
      INSERT new rows;
      COMMIT;
      ```

1. Evite transações de longa execução, ativas ou inativas, que possam ficar bloqueadas. Isso inclui sessões interativas do cliente MySQL que podem ficar abertas por um longo período com uma transação não confirmada. Ao otimizar os tamanhos das transações ou dos lotes, o impacto pode variar dependendo de vários fatores, como simultaneidade, número de duplicatas e estrutura da tabela. Todas as alterações devem ser implementadas e testadas com base em sua workload.

1. Em algumas situações, deadlocks podem ocorrer quando duas transações tentam acessar os mesmos conjuntos de dados, em uma ou várias tabelas, em ordens diferentes. Para evitar isso, você pode modificar as transações para acessar os dados na mesma ordem, serializando o acesso. Por exemplo, crie uma fila de transações a serem concluídas. Essa abordagem pode ajudar a evitar deadlocks quando ocorrem várias transações simultaneamente.

1. Adicionar índices cuidadosamente escolhidos às suas tabelas pode melhorar a seletividade e reduzir a necessidade de acessar linhas, o que ocasiona menos bloqueios.

1. Se você encontrar um [bloqueio de lacunas](https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html#innodb-gap-locks), poderá modificar o nível de isolamento da transação `READ COMMITTED` para a sessão ou a transação a fim de evitá-lo. Para ter mais informações sobre os níveis de isolamento do InnoDB e seus comportamentos, consulte [Níveis de isolamento de transações](https://dev.mysql.com/doc/refman/5.7/en/innodb-transaction-isolation-levels.html) na documentação do MySQL.

**nota**  
Embora você possa tomar precauções para reduzir a possibilidade de ocorrência de deadlocks, eles são um comportamento esperado do banco de dados e ainda podem ocorrer. As aplicações devem ter a lógica necessária para lidar com deadlocks ao encontrá-los. Por exemplo, implemente a lógica de repetição e recuo na aplicação. É melhor resolver a causa raiz do problema, mas, se ocorrer um deadlock, a aplicação terá a opção de esperar e tentar novamente.

### Monitorar deadlocks do InnoDB
<a name="AuroraMySQL.BestPractices.deadlocks-monitor"></a>

[Deadlocks](https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_deadlock) podem ocorrer no MySQL quando as transações da aplicação tentam fazer um bloqueio em nível de tabela e linha de uma forma que resulta em espera circular. Um deadlock ocasional do InnoDB não é necessariamente um problema, porque o mecanismo de armazenamento do InnoDB detecta a condição imediatamente e reverte uma das transações de forma automática. Se você se deparar com deadlocks com frequência, recomendamos revisar e modificar sua aplicação para amenizar problemas de performance e evitá-los. Quando a [detecção de deadlocks](https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_deadlock_detection) está ativada (o padrão), o InnoDB os detecta automaticamente nas transações e reverte uma ou mais transações para romper o deadlock. O InnoDB tenta selecionar pequenas transações para reverter, caso em que o tamanho de uma transação é determinado pelo número de linhas inseridas, atualizadas ou excluídas.
+ Instrução `SHOW ENGINE`: a instrução `SHOW ENGINE INNODB STATUS \G` contém [detalhes](https://dev.mysql.com/doc/refman/5.7/en/show-engine.html) do deadlock mais recente encontrado no banco de dados desde a última reinicialização.
+ Log de erros do MySQL: se você encontrar deadlocks frequentes em que a saída da instrução `SHOW ENGINE` é inadequada, você poderá ativar o parâmetro de cluster de banco de dados [innodb\$1print\$1all\$1deadlocks](https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_print_all_deadlocks).

  Quando esse parâmetro é ativado, as informações sobre todos os deadlocks nas transações do usuário do InnoDB são registradas no [log de erros](https://dev.mysql.com/doc/refman/8.0/en/error-log.html) do Aurora MySQL.
+ Métricas do Amazon CloudWatch: também recomendamos que você monitore proativamente os deadlocks usando a métrica do CloudWatch `Deadlocks`. Para ter mais informações, consulte [Métricas no nível da instância do Amazon Aurora](Aurora.AuroraMonitoring.Metrics.md#Aurora.AuroraMySQL.Monitoring.Metrics.instances).
+ Amazon CloudWatch Logs: com o CloudWatch Logs, você pode visualizar métricas, analisar dados de log e criar alarmes em tempo real. Para ter mais informações, consulte [Monitorar erros no Amazon Aurora MySQL e no Amazon RDS para MySQL usando o Amazon CloudWatch e enviar notificações usando o Amazon SNS](https://aws.amazon.com/blogs/database/monitor-errors-in-amazon-aurora-mysql-and-amazon-rds-for-mysql-using-amazon-cloudwatch-and-send-notifications-using-amazon-sns/).

  Usando o CloudWatch Logs com `innodb_print_all_deadlocks` ativado, você pode configurar alarmes para receber notificação quando o número de deadlocks exceder determinado limite. Para definir um limite, recomendamos que você observe suas tendências e use um valor com base em sua workload normal.
+ Performance Insights: ao usar o Performance Insights, você pode monitorar as métricas `innodb_deadlocks` e `innodb_lock_wait_timeout`. Para ter mais informações sobre essas métricas, consulte [Contadores não nativos para o Aurora MySQL](USER_PerfInsights_Counters.md#USER_PerfInsights_Counters.Aurora_MySQL.NonNative).