O ApsaraDB for ClickHouse oferece suporte a quatro famílias de motores de tabela: MergeTree, Log, Integrations e Special. Cada família é otimizada para um conjunto diferente de cargas de trabalho. Este tópico descreve a função de cada motor e apresenta exemplos dos motores mais utilizados.
Visão geral das famílias de motores
|
Família |
Ideal para |
Motores |
|
MergeTree |
Inserções de alto throughput com processamento em segundo plano, particionamento e replicação |
MergeTree, ReplacingMergeTree, CollapsingMergeTree, VersionedCollapsingMergeTree, SummingMergeTree, AggregatingMergeTree, GraphiteMergeTree, Índices de busca por vizinho mais próximo aproximado, Busca de texto completo usando índices invertidos |
|
Log |
Gravações rápidas em tabelas pequenas (~1 milhão de linhas) com leituras de tabela completa |
TinyLog, StripeLog, Log |
|
Integrations |
Importação ou consulta de fontes de dados externas |
Kafka, MySQL, JDBC, ODBC, HDFS |
|
Special |
Necessidades arquiteturais específicas (consultas distribuídas, visualizações materializadas, tabelas em memória) |
Distributed, MaterializedView, Dictionary, Merge, File, NULL, Set, Join, URL, View, Memory, Buffer |
Para obter uma referência completa de todos os motores de tabela suportados, consulte Motores de tabela.
Família MergeTree
Os motores da família MergeTree são a principal escolha para cargas de trabalho em produção. Eles oferecem suporte a inserções de alta velocidade, particionamento de dados, índices de chave primária, índices esparsos, amostragem de dados, replicação de dados e tempo de vida (TTL) para dados.
Todos os motores MergeTree compartilham a mesma estrutura de armazenamento: os dados são gravados em partes e mesclados em segundo plano, de forma semelhante a uma árvore de mesclagem estruturada em log (árvore LSM). O processamento na camada de armazenamento — incluindo deduplicação, colapso e agregação — ocorre durante a compactação, e não no momento da inserção.
O MergeTree no ApsaraDB for ClickHouse suporta toda a sintaxe SQL do ClickHouse, mas as chaves primárias funcionam de maneira diferente do SQL padrão. A chave primária acelera as consultas em vez de impor unicidade. Chaves primárias duplicadas podem existir mesmo após a compactação.
MergeTree
O MergeTree é o motor base para cargas de trabalho de inserção com alta demanda. Os dados são inseridos em partes e mesclados em segundo plano com base na ordem de classificação definida por ORDER BY.
Exemplo: MergeTree com particionamento
-
Crie uma tabela particionada por
create_timee ordenada por(id, create_time).CREATE TABLE test_tbl ON CLUSTER default ( id UInt16, create_time Date, comment Nullable(String) ) ENGINE = MergeTree() PARTITION BY create_time ORDER BY (id, create_time) PRIMARY KEY (id, create_time) SETTINGS index_granularity=8192; -
Insira linhas com chaves primárias duplicadas.
INSERT INTO test_tbl VALUES (1, '2019-12-13', null); INSERT INTO test_tbl VALUES (1, '2019-12-13', null); INSERT INTO test_tbl VALUES (2, '2019-12-14', null); INSERT INTO test_tbl VALUES (3, '2019-12-15', null); INSERT INTO test_tbl VALUES (3, '2019-12-15', null); -
Consulte a tabela.
SELECT * FROM test_tbl;Resultado — todas as cinco linhas retornadas, incluindo duplicatas:
┌─id─┬─create_time─┬─comment──┐ │ 1 │ 2019-12-13 │ NULL │ │ 1 │ 2019-12-13 │ NULL │ │ 2 │ 2019-12-14 │ NULL │ │ 3 │ 2019-12-15 │ NULL │ │ 3 │ 2019-12-15 │ NULL │ └────┴─────────────┴──────────┘ -
Force a compactação.
OPTIMIZE TABLE test_tbl FINAL; -
Consulte novamente.
SELECT * FROM test_tbl;Resultado — as duplicatas ainda estão presentes. O MergeTree não as remove.
┌─id─┬─create_time─┬─comment──┐ │ 1 │ 2019-12-13 │ NULL │ │ 1 │ 2019-12-13 │ NULL │ │ 2 │ 2019-12-14 │ NULL │ │ 3 │ 2019-12-15 │ NULL │ │ 3 │ 2019-12-15 │ NULL │ └────┴─────────────┴──────────┘
Para mais informações, consulte MergeTree.
ReplacingMergeTree
O ReplacingMergeTree remove linhas duplicadas com a mesma chave primária durante a compactação em segundo plano. Utilize este motor quando a deduplicação eventual for aceitável, pois ele não garante unicidade no momento da consulta.
Limitações
Em um cluster distribuído, linhas com a mesma chave primária podem ser armazenadas em shards diferentes. A deduplicação ocorre apenas dentro de um único shard, e não entre shards.
Antes da conclusão da compactação, algumas duplicatas ainda podem estar presentes. A compactação é executada em segundo plano em intervalos imprevisíveis.
Em grandes conjuntos de dados, a execução manual de
OPTIMIZE ... FINALpode levar muito tempo, tornando a deduplicação em tempo real impraticável.
Para mais informações, consulte ReplacingMergeTree.
Exemplo: Deduplicação com ReplacingMergeTree
-
Crie uma tabela.
CREATE TABLE test_tbl_replacing ( id UInt16, create_time Date, comment Nullable(String) ) ENGINE = ReplacingMergeTree() PARTITION BY create_time ORDER BY (id, create_time) PRIMARY KEY (id, create_time) SETTINGS index_granularity=8192; -
Insira linhas com chaves primárias duplicadas.
INSERT INTO test_tbl_replacing VALUES (1, '2019-12-13', null); INSERT INTO test_tbl_replacing VALUES (1, '2019-12-13', null); INSERT INTO test_tbl_replacing VALUES (2, '2019-12-14', null); INSERT INTO test_tbl_replacing VALUES (3, '2019-12-15', null); INSERT INTO test_tbl_replacing VALUES (3, '2019-12-15', null); -
Consulte antes da compactação — as duplicatas ainda estão presentes.
SELECT * FROM test_tbl_replacing;┌─id─┬─create_time─┬─comment──┐ │ 1 │ 2019-12-13 │ NULL │ │ 1 │ 2019-12-13 │ NULL │ │ 2 │ 2019-12-14 │ NULL │ │ 3 │ 2019-12-15 │ NULL │ │ 3 │ 2019-12-15 │ NULL │ └────┴─────────────┴──────────┘ -
Force a compactação.
OPTIMIZE TABLE test_tbl_replacing FINAL; -
Consulte novamente — duplicatas removidas.
SELECT * FROM test_tbl_replacing;┌─id─┬─create_time─┬─comment──┐ │ 1 │ 2019-12-13 │ NULL │ │ 2 │ 2019-12-14 │ NULL │ │ 3 │ 2019-12-15 │ NULL │ └────┴─────────────┴──────────┘
CollapsingMergeTree
O CollapsingMergeTree rastreia alterações de estado das linhas usando uma coluna Sign em vez de atualizar as linhas diretamente, já que atualizações são custosas no modelo de armazenamento append-only do ClickHouse. Cada linha é marcada como uma linha de estado (Sign = 1) ou uma linha de cancelamento (Sign = -1). Durante a compactação, pares de linhas de estado e de cancelamento com a mesma chave primária são colapsados e removidos.
Como funciona o colapso
Para atualizar o estado de uma linha:
Insira uma linha de cancelamento com
Sign = -1e os mesmos valores de chave primária da linha que você deseja substituir.Insira uma nova linha de estado com
Sign = 1e os valores atualizados.
Para excluir o estado de uma linha: insira uma linha de cancelamento que corresponda à linha de estado original em todas as colunas, exceto Sign.
Observações de uso
Se as linhas de estado e de cancelamento forem inseridas fora de ordem — por exemplo, se uma linha de cancelamento for inserida e sua linha de estado correspondente chegar separadamente — elas podem não ser colapsadas corretamente. Considere usar o VersionedCollapsingMergeTree para lidar com inserções fora de ordem.
O colapso ocorre apenas dentro de um único shard. Em um cluster distribuído, linhas com a mesma chave primária em nós diferentes não são colapsadas.
-
Antes da conclusão da compactação, as linhas de estado e de cancelamento coexistem. Ao executar consultas agregadas antes da compactação, ajuste seu SQL:
Substitua
COUNT()porSUM(Sign)Substitua
SUM(col)porSUM(col * Sign)
Para mais informações, consulte CollapsingMergeTree.
Exemplo: Atualizações de estado com CollapsingMergeTree
-
Crie uma tabela com uma coluna
Sign.CREATE TABLE test_tbl_collapsing ( UserID UInt64, PageViews UInt8, Duration UInt8, Sign Int8 ) ENGINE = CollapsingMergeTree(Sign) ORDER BY UserID; -
Insira a linha de estado inicial.
INSERT INTO test_tbl_collapsing VALUES (4324182021466249494, 5, 146, 1); -
Atualize o estado: insira uma linha de cancelamento para o estado antigo e uma nova linha de estado.
NotaInsira a linha de cancelamento e a nova linha de estado no mesmo lote. Se você inserir a linha de cancelamento e depois a linha de estado em operações separadas, elas podem chegar fora de ordem. Nesse caso, mesmo que a compactação seja forçada, as linhas com a mesma chave primária não poderão ser colapsadas ou excluídas.
INSERT INTO test_tbl_collapsing VALUES (4324182021466249494, 5, 146, -1), -- cancel old state (4324182021466249494, 6, 185, 1); -- new state -
Consulte antes da compactação — todas as três linhas estão presentes.
SELECT * FROM test_tbl_collapsing;┌────────UserID───────┬─PageViews─┬─Duration─┬─Sign──┐ │ 4324182021466249494 │ 5 │ 146 │ 1 │ │ 4324182021466249494 │ 5 │ 146 │ -1 │ │ 4324182021466249494 │ 6 │ 185 │ 1 │ └─────────────────────┴───────────┴──────────┴───────┘Para obter resultados agregados corretos antes da compactação, use expressões que considerem a coluna
Sign:SELECT UserID, SUM(PageViews * Sign) AS PageViews, SUM(Duration * Sign) AS Duration FROM test_tbl_collapsing GROUP BY UserID HAVING SUM(Sign) > 0;┌────────UserID───────┬─PageViews─┬─Duration──┐ │ 4324182021466249494 │ 6 │ 185 │ └─────────────────────┴───────────┴───────────┘ -
Force a compactação.
OPTIMIZE TABLE test_tbl_collapsing FINAL; -
Consulte novamente — apenas a linha de estado mais recente permanece.
SELECT * FROM test_tbl_collapsing;┌────────UserID───────┬─PageViews─┬─Duration─┬─Sign──┐ │ 4324182021466249494 │ 6 │ 185 │ 1 │ └─────────────────────┴───────────┴──────────┴───────┘
VersionedCollapsingMergeTree
O VersionedCollapsingMergeTree estende o CollapsingMergeTree com uma coluna Version que permite ao motor corresponder corretamente as linhas de estado e de cancelamento, independentemente da ordem de inserção. Durante a compactação, linhas com a mesma chave primária, o mesmo valor de Version e valores opostos de Sign são colapsadas e removidas.
Utilize este motor quando as linhas puderem chegar fora de ordem — por exemplo, em pipelines orientados a eventos onde eventos de cancelamento podem ser processados antes dos eventos de estado aos quais se referem.
Assim como no CollapsingMergeTree, ajuste as consultas agregadas para usar SUM(Sign) em vez de COUNT() e SUM(col * Sign) em vez de SUM(col).
Para mais informações, consulte VersionedCollapsingMergeTree.
Exemplo: VersionedCollapsingMergeTree com inserções fora de ordem
-
Crie uma tabela com as colunas
SigneVersion.CREATE TABLE test_tbl_Versioned ( UserID UInt64, PageViews UInt8, Duration UInt8, Sign Int8, Version UInt8 ) ENGINE = VersionedCollapsingMergeTree(Sign, Version) ORDER BY UserID; -
Insira primeiro uma linha de cancelamento (fora de ordem).
INSERT INTO test_tbl_Versioned VALUES (4324182021466249494, 5, 146, -1, 1); -
Insira a linha de estado correspondente e uma nova linha de estado.
INSERT INTO test_tbl_Versioned VALUES (4324182021466249494, 5, 146, 1, 1), -- state row matching the cancel above (4324182021466249494, 6, 185, 1, 2); -- new state -
Consulte antes da compactação.
SELECT * FROM test_tbl_Versioned;┌────────UserID───────┬─PageViews─┬─Duration─┬─Sign───┬Version─┐ │ 4324182021466249494 │ 5 │ 146 │ -1 │ 1 │ │ 4324182021466249494 │ 5 │ 146 │ 1 │ 1 │ │ 4324182021466249494 │ 6 │ 185 │ 1 │ 2 │ └─────────────────────┴───────────┴──────────┴────────┴────────┘Use agregação ciente da coluna
Signpara obter resultados corretos antes da compactação:SELECT UserID, SUM(PageViews * Sign) AS PageViews, SUM(Duration * Sign) AS Duration FROM test_tbl_Versioned GROUP BY UserID HAVING SUM(Sign) > 0;┌────────UserID───────┬─PageViews─┬─Duration─┐ │ 4324182021466249494 │ 6 │ 185 │ └─────────────────────┴───────────┴──────────┘ -
Force a compactação.
OPTIMIZE TABLE test_tbl_Versioned FINAL; -
Consulte novamente — a coluna
Versioncorrespondeu corretamente às linhas de cancelamento e de estado, apesar da inserção fora de ordem.SELECT * FROM test_tbl_Versioned;┌────────UserID───────┬─PageViews─┬─Duration─┬─Sign───┬Version─┐ │ 4324182021466249494 │ 6 │ 185 │ 1 │ 2 │ └─────────────────────┴───────────┴──────────┴────────┴────────┘
SummingMergeTree
Recomendamos usar o SummingMergeTree em conjunto com o MergeTree. Armazene os dados detalhados brutos em uma tabela MergeTree e utilize o SummingMergeTree para resultados pré-agregados. Isso evita perda de dados caso sua chave primária seja composta incorretamente.
O SummingMergeTree pré-agrega linhas com a mesma chave primária em uma única linha somando colunas numéricas. Isso reduz o armazenamento e acelera consultas agregadas.
Observações de uso
A pré-agregação ocorre durante a compactação em segundo plano, e não no momento da inserção. Alguns dados podem ainda não estar agregados, portanto, inclua sempre uma cláusula
GROUP BYcomSUM()em suas consultas.Apenas colunas numéricas são somadas. Colunas de string e outras colunas não numéricas que não fazem parte da chave primária recebem um valor arbitrário após a agregação.
Para mais informações, consulte SummingMergeTree.
Exemplo: Pré-agregação com SummingMergeTree
-
Crie uma tabela.
CREATE TABLE test_tbl_summing ( key UInt32, value UInt32 ) ENGINE = SummingMergeTree() ORDER BY key; -
Insira linhas — algumas compartilham a mesma chave.
INSERT INTO test_tbl_summing VALUES (1, 1), (1, 2), (2, 1); -
Consulte antes da compactação — linhas ainda não agregadas.
SELECT * FROM test_tbl_summing;┌─key─┬value─┐ │ 1 │ 1 │ │ 1 │ 2 │ │ 2 │ 1 │ └─────┴──────┘ -
Force a compactação.
OPTIMIZE TABLE test_tbl_summing FINAL; -
Consulte com
GROUP BYeSUM()para obter resultados corretos.SELECT key, SUM(value) FROM test_tbl_summing GROUP BY key;┌─key─┬value─┐ │ 1 │ 3 │ │ 2 │ 1 │ └─────┴──────┘
AggregatingMergeTree
O AggregatingMergeTree é um motor de pré-agregação mais flexível que suporta qualquer função de agregação, não apenas SUM. Ele utiliza o tipo de dados especial AggregateFunction e um padrão de consulta em duas fases:
Fase de escrita: use funções com o sufixo
-State(por exemplo,sumState,uniqState) para armazenar estados intermediários de agregação.Fase de consulta: use funções com o sufixo
-Merge(por exemplo,sumMerge,uniqMerge) para finalizar a agregação.
O AggregatingMergeTree é utilizado de duas formas: com uma visualização materializada (que automatiza a fase de escrita) ou diretamente com colunas AggregateFunction.
Para mais informações, consulte AggregatingMergeTree.
Exemplo 1: AggregatingMergeTree com uma visualização materializada
-
Crie uma tabela de detalhes.
CREATE TABLE visits ( UserID UInt64, CounterID UInt8, StartDate Date, Sign Int8 ) ENGINE = CollapsingMergeTree(Sign) ORDER BY UserID; -
Crie uma visualização materializada que pré-agregue a tabela de detalhes usando funções
-State.CREATE MATERIALIZED VIEW visits_agg_view ENGINE = AggregatingMergeTree() PARTITION BY toYYYYMM(StartDate) ORDER BY (CounterID, StartDate) AS SELECT CounterID, StartDate, sumState(Sign) AS Visits, uniqState(UserID) AS Users FROM visits GROUP BY CounterID, StartDate; -
Insira dados na tabela de detalhes. A visualização materializada é atualizada automaticamente.
INSERT INTO visits VALUES (0, 0, '2019-11-11', 1); INSERT INTO visits VALUES (1, 1, '2019-11-12', 1); -
Consulte a visualização materializada usando funções
-Merge.NotaUse
sumMergeeuniqMerge— as funções simplessumeuniqnão conseguem processar colunasAggregateFunctione retornarão um erro.SELECT StartDate, sumMerge(Visits) AS Visits, uniqMerge(Users) AS Users FROM visits_agg_view GROUP BY StartDate ORDER BY StartDate;┌──StartDate──┬─Visits─┬─Users──┐ │ 2019-11-11 │ 1 │ 1 │ │ 2019-11-12 │ 1 │ 1 │ └─────────────┴────────┴────────┘
Exemplo 2: AggregatingMergeTree com colunas AggregateFunction
-
Crie uma tabela de detalhes.
CREATE TABLE detail_table ( CounterID UInt8, StartDate Date, UserID UInt64 ) ENGINE = MergeTree() PARTITION BY toYYYYMM(StartDate) ORDER BY (CounterID, StartDate); -
Insira dados.
INSERT INTO detail_table VALUES (0, '2019-11-11', 1); INSERT INTO detail_table VALUES (1, '2019-11-12', 1); -
Crie uma tabela de agregação com uma coluna
AggregateFunction.CREATE TABLE agg_table ( CounterID UInt8, StartDate Date, UserID AggregateFunction(uniq, UInt64) ) ENGINE = AggregatingMergeTree() PARTITION BY toYYYYMM(StartDate) ORDER BY (CounterID, StartDate); -
Insira dados agregados usando
uniqState.NotaInsira usando um
SELECTcom funções-State. Um comandoINSERT INTO ... VALUESdireto com valores brutos falhará com um erro de tipo.INSERT INTO agg_table SELECT CounterID, StartDate, uniqState(UserID) FROM detail_table GROUP BY CounterID, StartDate; -
Consulte a tabela de agregação usando
uniqMerge.SELECT uniqMerge(UserID) AS state FROM agg_table GROUP BY CounterID, StartDate;┌─state─┐ │ 1 │ │ 1 │ └───────┘
Família Log
Os motores da família Log são projetados para gravações rápidas em tabelas pequenas (cerca de um milhão de linhas) onde toda a tabela é lida de uma só vez.
Características comuns a todos os motores Log:
Os dados são anexados ao disco sequencialmente
DELETEeUPDATEnão são suportadosÍndices não são suportados
Os dados não são gravados atomicamente
INSERTbloqueiaSELECTna mesma tabela
|
Motor |
Leituras concorrentes |
Layout de armazenamento |
Quando usar |
|
Não |
Um arquivo por coluna |
Dados intermediários temporários onde o desempenho não é crítico |
|
|
Sim |
Todas as colunas em um único arquivo |
Maior desempenho de consulta que o TinyLog com menos manipuladores de arquivos |
|
|
Sim |
Um arquivo por coluna |
Maior desempenho de consulta que o TinyLog com acesso por coluna |
Família Integrations
Os motores da família Integrations conectam o ApsaraDB for ClickHouse a fontes de dados externas, seja importando dados ou consultando-os no local.
|
Motor |
Descrição |
|
Kafka |
Lê dados de tópicos do Kafka para o ApsaraDB for ClickHouse |
|
MySQL |
Consulta tabelas MySQL diretamente do ApsaraDB for ClickHouse usando |
|
JDBC |
Conecta-se a fontes de dados via strings de conexão Java Database Connectivity (JDBC) |
|
ODBC |
Conecta-se a fontes de dados via strings de conexão Open Database Connectivity (ODBC) |
|
HDFS |
Lê arquivos em um formato especificado do Hadoop Distributed File System (HDFS) |
Família Special
Os motores da família Special atendem a necessidades arquiteturais específicas.
|
Motor |
Descrição |
|
Distributed |
Não armazena dados. Roteia consultas para múltiplos shards e agrega os resultados. |
|
MaterializedView |
Armazena resultados de consultas pré-computados. Usado para criar visualizações materializadas. |
|
Dictionary |
Expõe dados de dicionário como uma tabela consultável. |
|
Merge |
Não armazena dados. Lê de várias tabelas simultaneamente como uma união virtual. |
|
File |
Usa um arquivo local como armazenamento de dados. |
|
NULL |
Descarta todos os dados gravados. As leituras retornam resultados vazios. Útil como destino para visualizações materializadas durante testes. |
|
Set |
Sempre armazena dados na memória de acesso aleatório (RAM). |
|
Join |
Armazena dados de junção na RAM para busca rápida. |
|
URL |
Lê e grava em endpoints HTTP ou HTTPS remotos. |
|
View |
Armazena uma definição de consulta |
|
Memory |
Armazena dados na RAM. Os dados são perdidos quando o servidor reinicia. Adequado para tabelas temporárias com menos de 100 milhões de linhas e sem requisitos de persistência de dados. Comumente usado para tabelas temporárias no ApsaraDB for ClickHouse. |
|
Buffer |
Armazena gravações em buffer na RAM e descarrega para uma tabela de destino quando limiares configuráveis são atingidos. |