Comparar DML e mutações

Linguagem de manipulação de dados (DML, na sigla em inglês) e mutações são duas APIs no Spanner que podem ser usadas para modificar dados. Cada uma oferece recursos semelhantes de manipulação de dados. Esta página compara as duas abordagens.

O que é linguagem de manipulação de dados (DML)?

A linguagem de manipulação de dados (DML, na sigla em inglês) no Spanner permite manipular dados nas tabelas do banco de dados usando instruções INSERT, UPDATE e DELETE. É possível executar instruções DML usando as bibliotecas de cliente, o Console do Google Cloud e a gcloud spanner.

O Spanner oferece as duas implementações a seguir de execução da DML, cada uma com propriedades diferentes.

  • DML padrão: adequado para cargas de trabalho padrão de processamento de transações on-line (OLTP, na sigla em inglês).

    Para mais informações, incluindo exemplos de código, consulte Como usar DML.

  • DML particionada: projetada para atualizações e exclusões em massa, como nos exemplos a seguir.

    • Limpeza periódica e coleta de lixo. Alguns exemplos são excluir linhas antigas ou definir colunas como NULL.

    • Preenchimento de novas colunas com valores padrão. Um exemplo é usar uma instrução UPDATE para definir o valor de uma nova coluna como False, em que ele é NULL.

    Para mais informações, incluindo exemplos de código, consulte Como usar DML particionada.

    É possível usar gravações em lote para um grande número de operações de gravação sem operações de leitura que não exijam transações atômicas. Para mais informações, consulte Modificar dados usando gravações em lote.

O que são mutações?

Uma mutação representa uma sequência de inserções, atualizações e exclusões que o Spanner aplica atomicamente a diferentes linhas e tabelas em um banco de dados. É possível incluir operações que se aplicam a linhas ou tabelas diferentes em uma mutação. Depois de definir uma ou mais mutações que contêm uma ou mais gravações, é necessário aplicar a mutação para confirmar as gravações. Cada alteração é aplicada na ordem em que foram adicionadas à mutação.

Para mais informações, incluindo exemplos de código, consulte Como inserir, atualizar e excluir dados usando mutações.

Comparação de recursos entre DML e mutações

A tabela a seguir resume o suporte à DML e à mutação da operação e dos recursos comuns do banco de dados.

Operações DML Mutações
Inserir dados Compatível Compatível
Excluir dados Compatível Compatível
Atualizar dados Compatível Compatível
Inserir ou ignorar dados Compatível Sem suporte
Leia suas gravações (RYM, na sigla em inglês) Compatível Sem suporte
Inserir ou atualizar dados (inserir ou atualizar) Compatível Compatível
Sintaxe SQL Compatível Sem suporte
Verificação de restrição Após cada instrução No momento da confirmação

A DML e as mutações divergem no suporte aos seguintes recursos:

  • Leitura das gravações: leitura de resultados não confirmados em uma transação ativa. As alterações feitas com instruções DML ficam visíveis para instruções subsequentes na mesma transação. Isso é diferente de usar mutações, em que as alterações não são visíveis em nenhuma leitura (incluindo leituras feitas na mesma transação) até a confirmação da transação. Isso ocorre porque as mutações em uma transação são armazenadas no lado do cliente (localmente) e enviadas ao servidor como parte da operação de confirmação. Como resultado, as mutações na solicitação de confirmação não são visíveis para as instruções SQL ou DML na mesma transação.

  • Verificação de restrição: o Spanner verifica as restrições após cada instrução DML. Isso é diferente de usar mutações, em que o Spanner armazena mutações no cliente até confirmar e verificar as restrições no momento da confirmação. A avaliação de restrições após cada instrução DML permite que o Spanner garanta que os dados retornados por uma consulta subsequente na mesma transação retornem dados consistentes com o esquema.

  • Sintaxe SQL: a DML oferece uma maneira convencional de manipular dados. É possível reutilizar as habilidades do SQL para alterar os dados com a API DML.

Prática recomendada: evite misturar DML e mutação na mesma transação

Se uma transação contiver instruções DML e mutações na solicitação de confirmação, o Spanner executará as instruções DML antes das mutações. Para não precisar incluir a ordem de execução no código da biblioteca de cliente, use instruções DML ou as mutações em uma única transação, mas não ambas.

O exemplo de Java a seguir ilustra um comportamento potencialmente surpreendente. O código insere duas linhas nos álbuns usando a API de mutação. O snippet, em seguida, chama executeUpdate() para atualizar as linhas recém-inseridas e chama executeQuery() para ler os álbuns atualizados.

static void updateMarketingBudget(DatabaseClient dbClient) {
  dbClient
      .readWriteTransaction()
      .run(
          new TransactionCallable<Void>() {
            @Override
            public Void run(TransactionContext transaction) throws Exception {
               transaction.buffer(
                    Mutation.newInsertBuilder("Albums")
                        .set("SingerId")
                        .to(1)
                        .set("AlbumId")
                        .to(1)
                        .set("AlbumTitle")
                        .to("Total Junk")
                        .set("MarketingBudget")
                        .to(800)
                        .build());
               transaction.buffer(
                    Mutation.newInsertBuilder("Albums")
                        .set("SingerId")
                        .to(1)
                        .set("AlbumId")
                        .to(2)
                        .set("AlbumTitle")
                        .to("Go Go Go")
                        .set("MarketingBudget")
                        .to(200)
                        .build());

                // This UPDATE will not include the Albums inserted above.
                String sql =
                  "UPDATE Albums SET MarketingBudget = MarketingBudget * 2"
                      + " WHERE SingerId = 1";
                long rowCount = transaction.executeUpdate(Statement.of(sql));
                System.out.printf("%d records updated.\n", rowCount);

                // Read a newly updated record.
                sql =
                  "SELECT SingerId, AlbumId, AlbumTitle FROM Albums"
                      + " WHERE SingerId = 1 AND MarketingBudget < 1000";
                ResultSet resultSet =
                                 transaction.executeQuery(Statement.of(sql));
                while (resultSet.next()) {
                   System.out.printf(
                        "%s %s\n",
                        resultSet.getString("FirstName"),
                        resultSet.getString("LastName"));
                }
                return null;
              }
            });
}

Se você executar esse código, verá 0 registros atualizados. Por quê? Isso acontece porque as alterações feitas com "Mutações" não ficam visíveis para as instruções subsequentes até que a transação seja confirmada. O ideal é ter gravações armazenadas em buffer somente no final da transação.

A seguir