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
UPDATEpara 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 ser 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 INDEXe 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 necessárias 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 elemento
INSERTnã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.
Práticas recomendadas
Aplique as seguintes práticas recomendadas para melhorar o desempenho das suas declarações DML particionadas:
- Evite a concorrência elevada: a execução de um grande número de declarações DML particionadas em simultâneo (por exemplo, mais de 100) pode levar a contenção de bloqueios em tabelas do sistema interno, o que degrada o desempenho. Em vez de executar um número elevado de declarações simultâneas, use uma única declaração DML particionada.
- Utilize
PDML_MAX_PARALLELISM: Para aumentar a taxa de transferência de uma única declaração DML particionada, especialmente em tabelas com muitas divisões, defina um valor mais elevado para a sugestão de declaraçãoPDML_MAX_PARALLELISM. Isto permite que a declaração única use mais paralelismo internamente. A definição de um valor mais elevado paraPDML_MAX_PARALLELISMresulta numa maior utilização de computação, pelo que deve tentar equilibrar a utilização de computação e o aumento da velocidade de processamento. - Deixe que o Spanner processe a divisão em partições: evite dividir manualmente os dados em fragmentos (por exemplo, usando intervalos de chaves primárias) e executar declarações DML divididas em partições separadas em cada fragmento. A DML particionada foi concebida para particionar o trabalho de forma eficiente em toda a tabela. A divisão personalizada aumenta frequentemente as despesas gerais e pode piorar a contenção.
- Compreenda o âmbito da partição: as operações DML particionadas são paralelizadas em todas as divisões na base de dados completa e não apenas nas divisões que contêm dados para a tabela que está a ser modificada. Isto significa que, para bases de dados com um grande número de divisões, pode haver sobrecarga, mesmo que a tabela de destino seja pequena ou os dados modificados estejam localizados. A DML particionada pode não ser a escolha mais eficiente para modificar uma parte muito pequena de uma base de dados grande.
- Considere alternativas para eliminações frequentes e pequenas: para exemplos de utilização que envolvam eliminações frequentes de um pequeno número de linhas conhecidas, a utilização de declarações DML em transações ou a API BatchWrite pode oferecer um melhor desempenho e uma sobrecarga inferior do que a utilização de DML particionada.
Exemplos
O seguinte exemplo de código 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.
Ir
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#
Ir
Java
Node.js
PHP
Python
Ruby
O que se segue?
Saiba como modificar dados com DML.
Saiba mais sobre as práticas recomendadas da linguagem de manipulação de dados (DML).
Para saber mais sobre as diferenças entre DML e mutações, consulte o artigo Compare DML and Mutations
Pondere usar o conetor do Dataflow para outros cenários de transformação de dados.