- A qualquer momento, sua tabela ainda pode ter duplicatas (linhas com a mesma chave de ordenação)
- A remoção efetiva de linhas duplicadas ocorre durante a mesclagem das partes
- Suas consultas precisam levar em conta a possibilidade de duplicatas
| O ClickHouse oferece treinamento gratuito sobre desduplicação e muitos outros tópicos. O módulo de treinamento Deleting and Updating Data é um bom ponto de partida. |
Opções de desduplicação
-
motor de tabela
ReplacingMergeTree: com esse motor de tabela, linhas duplicadas com a mesma chave de ordenação são removidas durante as mesclagens.ReplacingMergeTreeé uma boa opção para emular o comportamento de upsert (quando você quer que as consultas retornem a última linha inserida). -
Colapso de linhas: os motores de tabela
CollapsingMergeTreeeVersionedCollapsingMergeTreeusam uma lógica em que uma linha existente é “cancelada” e uma nova linha é inserida. Eles são mais complexos de implementar do queReplacingMergeTree, mas suas consultas e agregações podem ser mais simples de escrever, sem a preocupação de saber se os dados já foram mesclados ou não. Esses dois motores de tabela são úteis quando você precisa atualizar dados com frequência.
Usando ReplacingMergeTree para Upserts
views, insira uma nova linha com a mesma chave primária (observe os novos valores da coluna views):
FINAL na consulta SELECT, o que resulta em uma mesclagem lógica do resultado da consulta:
Usar
FINAL funciona bem se você tiver uma pequena quantidade de dados. Se estiver lidando com uma grande quantidade de dados,
usar FINAL provavelmente não é a melhor opção. Vamos ver uma alternativa melhor para
encontrar o valor mais recente de uma coluna.Evitando FINAL
views novamente nas duas linhas distintas:
FINAL).
FINAL, vamos aplicar uma lógica de negócio — sabemos que a coluna views está sempre aumentando, então podemos selecionar a linha com o maior valor usando a função max após agrupar pelas colunas desejadas:
FINAL.
Nosso Deleting and Updating Data training module aprofunda este exemplo, incluindo como usar uma coluna version com ReplacingMergeTree.
Usando CollapsingMergeTree para atualizar colunas com frequência
ALTER TABLE..UPDATE e, em vez disso, simplesmente inserir os novos dados ao lado dos dados existentes. Poderíamos adicionar uma coluna para indicar se os dados estão desatualizados ou são novos… e, na verdade, já existe um motor de tabela que implementa esse comportamento muito bem, especialmente porque exclui automaticamente os dados desatualizados para você. Vamos ver como isso funciona.
Suponha que rastreamos o número de visualizações de um comentário do Hacker News usando um sistema externo e, a cada poucas horas, enviamos os dados para o ClickHouse. Queremos que as linhas antigas sejam excluídas e que as novas linhas representem o novo estado de cada comentário do Hacker News. Podemos usar uma CollapsingMergeTree para implementar esse comportamento.
Vamos definir uma tabela para armazenar o número de visualizações:
hackernews_views tem uma coluna Int8 chamada sign, conhecida como coluna sign. O nome da coluna sign é arbitrário, mas o tipo de dado Int8 é obrigatório. Observe também que o nome da coluna foi passado para o construtor da tabela CollapsingMergeTree.
O que é a coluna sign de uma tabela CollapsingMergeTree? Ela representa o estado da linha, e a coluna sign só pode ser 1 ou -1. Veja como isso funciona:
- Se duas linhas tiverem a mesma chave primária (ou a mesma ordem de ordenação, se ela for diferente da chave primária), mas valores diferentes na coluna sign, então a última linha inserida com +1 se torna a linha de estado, e as outras linhas se anulam mutuamente
- As linhas que se anulam mutuamente são excluídas durante a mesclagem
- As linhas que não têm um par correspondente são mantidas
hackernews_views. Como ela é a única linha para esta chave primária, definimos seu estado como 1:
(123, 'ricardo'):
FINAL, é retornada a linha correspondente ao estado atual:
FINAL em tabelas grandes.
O valor informado para a coluna
views no nosso exemplo não é realmente necessário, nem precisa corresponder ao valor atual de views da linha antiga. Na verdade, você pode cancelar uma linha apenas com a chave primária e um -1:Atualizações em tempo real de várias threads
CollapsingMergeTree, as linhas se cancelam mutuamente usando uma coluna de sinal, e o estado de uma linha é determinado pela última linha inserida. Mas isso pode ser problemático se você estiver inserindo linhas de threads diferentes, em que as linhas podem ser inseridas fora de ordem. Usar a “última” linha não funciona nessa situação.
É aí que VersionedCollapsingMergeTree se torna útil - ele colapsa as linhas assim como CollapsingMergeTree, mas, em vez de manter a última linha inserida, mantém a linha com o maior valor em uma coluna de versão que você especifica.
Vamos ver um exemplo. Suponha que queremos rastrear o número de visualizações dos nossos comentários no Hacker News, e os dados sejam atualizados com frequência. Queremos que os relatórios usem os valores mais recentes sem forçar nem esperar por mesclagens. Começamos com uma tabela semelhante a CollapsedMergeTree, mas adicionamos uma coluna para armazenar a versão do estado da linha:
VersionsedCollapsingMergeTree como mecanismo e recebe a coluna de sinal e uma coluna de versão. Veja como a tabela funciona:
- Ela exclui cada par de linhas que têm a mesma chave primária e a mesma versão, mas sinais diferentes
- A ordem em que as linhas foram inseridas não importa
- Observe que, se a coluna de versão não fizer parte da chave primária, o ClickHouse a adiciona implicitamente à chave primária como o último campo
hackernews_views_vcmt:
VersionedCollapsingMergeTree é bastante útil quando você deseja implementar desduplicação ao inserir linhas de vários clientes e/ou threads.
Por que minhas linhas não estão sendo desduplicadas?
INSERT. Por exemplo, se você estiver inserindo linhas com a coluna createdAt DateTime64(3) DEFAULT now(), essas linhas serão necessariamente únicas, porque cada linha terá um valor padrão exclusivo para a coluna createdAt. O motor de tabela MergeTree / ReplicatedMergeTree não conseguirá desduplicar as linhas, já que cada linha inserida gerará um checksum exclusivo.
Nesse caso, você pode especificar seu próprio insert_deduplication_token para cada lote de linhas, garantindo que várias inserções do mesmo lote não façam com que as mesmas linhas sejam inseridas novamente. Consulte a documentação sobre insert_deduplication_token para mais detalhes sobre como usar essa configuração.