Compare DML e mutações

A linguagem de manipulação de dados (DML) e as mutações são duas APIs no Spanner que pode usar para modificar dados. Cada um oferece funcionalidades de manipulação de dados semelhantes. Esta página compara ambas as abordagens.

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

A linguagem de manipulação de dados (DML) no Spanner permite-lhe manipular dados nas tabelas da base de dados através das declarações INSERT, UPDATE e DELETE. Pode executar declarações DML através das bibliotecas de cliente, da Google Cloud consola e do gcloud spanner.

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

  • DML padrão: adequado para cargas de trabalho de processamento de transações online (OLTP) padrão.

    Para mais informações, incluindo exemplos de código, consulte o artigo Usar DML

  • DML particionada: concebida para atualizações e eliminações em massa, como nos exemplos seguintes.

    • Limpeza periódica e recolha de lixo. Exemplos: eliminar linhas antigas ou definir colunas como NULL.

    • Preencher novas colunas com valores predefinidos. Um exemplo é usar uma declaração UPDATE para definir o valor de uma nova coluna como Falso quando é NULL.

    Para mais informações, incluindo exemplos de código, consulte o artigo Usar DML particionada.

    Pode 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 o artigo Modifique dados através de gravações em lote.

O que são mutações?

Uma mutação representa uma sequência de inserções, atualizações e eliminações que o Spanner aplica atomicamente a diferentes linhas e tabelas numa base de dados. Pode incluir operações que se aplicam a diferentes linhas ou tabelas diferentes numa mutação. Depois de definir uma ou mais mutações que contenham uma ou mais escritas, tem de aplicar a mutação para confirmar as escritas. Cada alteração é aplicada pela ordem em que foi adicionada à mutação.

Para mais informações, incluindo exemplos de código, consulte o artigo Inserir, atualizar e eliminar dados através de mutações.

Comparação de funcionalidades entre a DML e as mutações

A tabela seguinte resume o suporte de DML e mutação das funcionalidades e operações comuns da base de dados.

Operações DML Mutações
Inserir dados Suportado Suportado
Elimine os dados Suportado Suportado
Atualizar dados Suportado Suportado
Inserir ou ignorar dados Suportado Não suportado
Ler as suas escritas (RYW) Suportado Não suportado
Inserir ou atualizar dados (Upsert) Suportado Suportado
Sintaxe SQL Suportado Não suportado
Verificação de restrições Após cada declaração No momento da confirmação

A DML e as mutações divergem no respetivo suporte para as seguintes funcionalidades:

  • Read Your Writes: leitura de resultados não comprometidos numa transação ativa. As alterações que fizer com declarações DML são visíveis para declarações subsequentes na mesma transação. Isto é diferente da utilização de mutações, em que as alterações não são visíveis em nenhuma leitura (incluindo leituras feitas na mesma transação) até que a transação seja confirmada. Isto deve-se ao facto de as mutações numa transação serem armazenadas em buffer do lado do cliente (localmente) e enviadas para o servidor como parte da operação de confirmação. Como resultado, as mutações no pedido de confirmação não são visíveis para as declarações SQL ou DML na mesma transação.

  • Verificação de restrições: o Spanner verifica as restrições após cada declaração DML. Isto é diferente da utilização de mutações, em que o Spanner armazena mutações em buffer no cliente até à confirmação e verifica as restrições no momento da confirmação. A avaliação das restrições após cada declaração DML permite ao Spanner garantir que os dados devolvidos por uma consulta subsequente na mesma transação devolvem dados consistentes com o esquema.

  • Sintaxe SQL: a DML oferece uma forma convencional de manipular dados. Pode reutilizar competências de SQL para alterar os dados através da API DML.

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

Se uma transação contiver declarações DML e mutações no pedido de confirmação, o Spanner executa as declarações DML antes das mutações. Para evitar ter de ter em conta a ordem de execução no código da biblioteca de cliente, deve usar instruções DML ou as mutações numa única transação, mas não ambas.

O exemplo em Java seguinte ilustra um comportamento potencialmente surpreendente. O código insere duas linhas em Albums através da API Mutation. O fragmento chama executeUpdate() para atualizar as linhas inseridas recentemente 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 executasse este código, veria 0 registos atualizados. Porquê? Isto acontece porque as alterações que fizemos através de mutações não são visíveis para as declarações subsequentes até a transação ser confirmada. Idealmente, devemos ter gravações em buffer apenas no final da transação.

O que se segue?