A linguagem de manipulação de dados particionada (DML particionada) foi concebida para os seguintes tipos de atualizações e eliminações em massa:
- 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 comoFalse
, quando atualmente éNULL
.
A DML particionada não é adequada para o processamento de transações em pequena escala. Se quiser executar uma declaração em algumas linhas, use DMLs transacionais com chaves primárias identificáveis. Para mais informações, consulte o artigo Usar DML.
Se precisar de confirmar um grande número de escritas cegas, mas não precisar de uma transação atómica, pode modificar em massa as tabelas do Spanner através da escrita em lote. Para mais informações, consulte o artigo Modifique dados através de gravações em lote.
Pode obter estatísticas sobre as consultas DML particionadas ativas e o respetivo progresso a partir das tabelas de estatísticas na sua base de dados do Spanner. Para mais informações, consulte o artigo Estatísticas de DMLs particionadas ativas.
DML e DML particionada
O Spanner suporta dois modos de execução para declarações DML:
DML, que é adequado para o processamento de transações. Para mais informações, consulte o artigo Usar DML.
DML particionada, que permite operações em grande escala em toda a base de dados com um impacto mínimo no processamento de transações simultâneas, através da partição do espaço de chaves e da execução da declaração em partições em transações separadas de âmbito mais reduzido. Para mais informações, consulte o artigo Usar DML particionada.
A tabela seguinte realça algumas das diferenças entre os dois modos de execução.
DML | DML particionada |
---|---|
As linhas que não correspondem à cláusula WHERE podem estar bloqueadas. |
Apenas as linhas que correspondem à cláusula WHERE são bloqueadas. |
Aplicam-se limites de tamanho das transações. | O Spanner processa os limites de transações e os limites de concorrência por transação. |
As declarações não têm de ser idempotentes. | Uma instrução DML tem de ser idempotente para garantir resultados consistentes. |
Uma transação pode incluir várias declarações DML e SQL. | Uma transação particionada só pode incluir uma declaração DML. |
Não existem restrições quanto à complexidade das declarações. | As declarações têm de ser totalmente divisíveis. |
Cria transações de leitura/escrita no seu código de cliente. | O Spanner cria as transações. |
Particionável e idempotente
Quando uma declaração DML particionada é executada, as linhas numa partição não têm acesso
a linhas noutras partições, e não pode escolher como o Spanner cria
as partições. A partição garante a escalabilidade, mas também significa que as declarações DML particionadas têm de ser totalmente particionáveis. Ou seja, a declaração DML particionada tem de ser expressa como a união de um conjunto de declarações, em que cada declaração acede a uma única linha da tabela e cada declaração não acede a outras tabelas. Por exemplo, uma declaração DML que acede a várias tabelas ou executa uma junção automática não é divisível em partições. Se a declaração DML não for particionável, o Spanner devolve o erro BadUsage
.
Estas declarações DML são totalmente divisíveis, porque cada declaração pode ser aplicada a uma única linha na tabela:
UPDATE Singers SET LastName = NULL WHERE LastName = '';
DELETE FROM Albums WHERE MarketingBudget > 10000;
Esta declaração DML não é totalmente particionável, porque acede a várias tabelas:
# Not fully partitionable
DELETE FROM Singers WHERE
SingerId NOT IN (SELECT SingerId FROM Concerts);
O Spanner pode executar uma declaração DML particionada várias vezes em algumas partições devido a novas tentativas ao nível da rede. Como resultado, uma declaração pode ser executada mais do que uma vez numa linha. Por conseguinte, a declaração tem de ser idempotente para gerar resultados consistentes. Uma declaração é idempotente se a execução da mesma várias vezes numa única linha produzir o mesmo resultado.
Esta instrução DML é idempotente:
UPDATE Singers SET MarketingBudget = 1000 WHERE true;
Esta instrução DML não é idempotente:
UPDATE Singers SET MarketingBudget = 1.5 * MarketingBudget WHERE true;
Elimine linhas de tabelas principais com tabelas secundárias indexadas
Quando usa uma declaração DML particionada para eliminar linhas numa tabela principal, a operação pode falhar com o erro: The transaction contains too many
mutations
. Isto ocorre se a tabela principal tiver tabelas secundárias intercaladas que contenham um índice global. As mutações nas linhas da tabela secundária em si não são
contabilizadas para o limite de mutações da transação.
No entanto, as mutações correspondentes às entradas do índice são contabilizadas. Se um grande número de entradas de índice da tabela secundária for afetado, a transação pode exceder o limite de mutação.
Para evitar este erro, elimine as linhas em duas declarações DML particionadas separadas:
- Executar uma eliminação particionada nas tabelas secundárias.
- Executar uma eliminação particionada na tabela principal.
Este processo de dois passos ajuda a manter a contagem de mutações dentro dos limites permitidos para cada transação. Em alternativa, pode eliminar o índice global na tabela secundária antes de eliminar as linhas principais.
Bloqueio de linhas
O Spanner adquire um bloqueio apenas se uma linha for candidata a atualização ou eliminação. Este comportamento é diferente da execução de DML, que pode bloquear a leitura de linhas que não correspondem à cláusula WHERE
.
Execução e transações
Se uma declaração DML é particionada ou não, depende do método da biblioteca do cliente que escolher para execução. Cada biblioteca de cliente fornece métodos separados para execução de DML e execução de DML particionada.
Só pode executar uma declaração DML particionada numa chamada ao método da biblioteca do cliente.
O Spanner não aplica as declarações DML particionadas de forma atómica em toda a tabela. No entanto, o Spanner aplica declarações DML particionadas de forma atómica em cada partição.
O DML particionado não suporta a confirmação nem a reversão. O Spanner executa e aplica a declaração DML imediatamente.
- Se cancelar a operação, o Spanner cancela as partições em execução e não inicia as partições restantes. O Spanner não reverte nenhuma partição que já tenha sido executada.
- Se a execução da declaração causar um erro, a execução é interrompida em todas as partições e o Spanner devolve esse erro para toda a operação. Alguns exemplos de erros são violações de restrições de tipo de dados, violações de
UNIQUE INDEX
e violações deON DELETE NO ACTION
. Consoante o momento em que a execução falhou, a declaração pode ter sido executada com êxito em algumas partições e pode nunca ter sido executada noutras partições.
Se a declaração DML particionada for bem-sucedida, o Spanner executou a declaração, pelo menos, uma vez em cada partição do intervalo de chaves.
Contagem de linhas modificadas
Uma declaração DML particionada devolve um limite inferior no número de linhas modificadas. Pode não ser uma contagem exata do número de linhas modificadas, porque não há garantia de que o Spanner conte todas as linhas modificadas.
Limites de transação
O Spanner cria as partições e as transações de que precisa para executar uma declaração DML particionada. Aplicam-se limites de transação ou limites de concorrência por transação, mas o Spanner tenta manter as transações dentro dos limites.
O Spanner permite um máximo de 20 000 declarações DML particionadas simultâneas por base de dados.
Funcionalidades não suportadas
O Spanner não suporta algumas funcionalidades para DML particionada:
- O
INSERT
não é suportado. - Google Cloud consola: não pode executar declarações DML particionadas na Google Cloud consola.
- Planos de consulta e criação de perfis: a CLI gcloud e as bibliotecas de cliente não suportam planos de consulta nem criação de perfis.
- Subconsultas que leem de outra tabela ou de uma linha diferente da mesma tabela.
Para cenários complexos, como mover uma tabela ou transformações que requerem junções entre tabelas, pondere usar o conetor do Dataflow.
Exemplos
O exemplo de código seguinte atualiza a coluna MarketingBudget
da tabela Albums
.
C++
Use a função ExecutePartitionedDml()
para executar uma declaração DML particionada.
C#
Usa o método ExecutePartitionedUpdateAsync()
para executar uma declaração DML particionada.
Go
Usa o método PartitionedUpdate()
para executar uma declaração DML particionada.
Java
Usa o método executePartitionedUpdate()
para executar uma declaração DML particionada.
Node.js
Usa o método runPartitionedUpdate()
para executar uma declaração DML particionada.
PHP
Usa o método executePartitionedUpdate()
para executar uma declaração DML particionada.
Python
Usa o método execute_partitioned_dml()
para executar uma declaração DML particionada.
Ruby
Usa o método execute_partitioned_update()
para executar uma declaração DML particionada.
O exemplo de código seguinte elimina linhas da tabela Singers
com base na coluna SingerId
.
C++
C#
Go
Java
Node.js
PHP
Python
Ruby
O que se segue?
Saiba como modificar dados usando DML.
Saiba mais sobre as práticas recomendadas da linguagem de manipulação de dados (DML).
Para saber mais sobre as diferenças entre a DML e as mutações, consulte o artigo Compare a DML e as mutações
Pondere usar o conetor do Dataflow para outros cenários de transformação de dados.