Esta seção se concentra em otimizar o desempenho da leitura e inserção de dados no S3 usando as funções de tabela do S3.
Antes de ajustar threads e tamanhos de bloco para melhorar o desempenho de inserção, recomendamos que os usuários entendam o mecanismo de inserção no S3. Se você já conhece esse processo, ou só quer algumas dicas rápidas, pule para o exemplo abaixo.
Mecanismos de inserção (nó único)
Dois fatores principais, além da capacidade do hardware, influenciam o desempenho e o consumo de recursos dos mecanismos de inserção de dados do ClickHouse (em um único nó): tamanho do bloco de inserção e paralelismo de inserção.
Tamanho do bloco de inserção

Ao executar um INSERT INTO SELECT, o ClickHouse recebe uma porção de dados e ① forma, a partir dos dados recebidos, (pelo menos) um bloco de inserção em memória (por chave de particionamento). Os dados do bloco são ordenados, e otimizações específicas do motor de tabela são aplicadas. Em seguida, os dados são compactados e ② gravados no armazenamento do banco de dados na forma de uma nova parte de dados.
O tamanho do bloco de inserção afeta tanto o uso de E/S de arquivos em disco quanto o uso de memória de um servidor ClickHouse. Blocos de inserção maiores consomem mais memória, mas geram partes iniciais maiores e em menor quantidade. Quanto menos partes o ClickHouse precisar criar para carregar um grande volume de dados, menor será a E/S de arquivos em disco e menor será a necessidade de mesclagens automáticas em segundo plano.
Ao usar uma consulta INSERT INTO SELECT em combinação com um motor de tabela de integração ou uma função de tabela, os dados são extraídos pelo servidor ClickHouse:

Até que os dados sejam totalmente carregados, o servidor executa um loop:
① Pull and parse the next portion of data and form an in-memory data block (one per partitioning key) from it.
② Write the block into a new part on storage.
Go to ① Em ①, o tamanho depende do tamanho do bloco de inserção, que pode ser controlado com duas configurações:
min_insert_block_size_rows(padrão:1048545linhas)min_insert_block_size_bytes(padrão:256 MiB)
Quando o número especificado de linhas for coletado no bloco de inserção, ou a quantidade de dados configurada for atingida (o que ocorrer primeiro), isso acionará a gravação do bloco em uma nova parte. O loop de inserção continua no passo ①.
Observe que o valor de min_insert_block_size_bytes indica o tamanho do bloco não compactado em memória (e não o tamanho da parte compactada em disco). Além disso, observe que os blocos e partes criados raramente contêm exatamente a quantidade configurada de linhas ou bytes, porque o ClickHouse faz streaming e processa os dados em blocos de linhas. Portanto, essas configurações especificam limites mínimos.
Atenção às mesclagens
Quanto menor for o tamanho do bloco de inserção configurado, mais partes iniciais serão criadas para uma grande carga de dados e mais mesclagens de partes em segundo plano serão executadas em paralelo à ingestão dos dados. Isso pode causar contenção de recursos (CPU e memória) e exigir tempo adicional (para atingir um número saudável (3000) de partes) após o término da ingestão.
O ClickHouse mescla partes continuamente em partes maiores até que elas atinjam um tamanho compactado de ~150 GiB. Este diagrama mostra como um servidor ClickHouse mescla partes:

Um único servidor ClickHouse utiliza várias threads de mesclagem em segundo plano para executar mesclagens de partes simultaneamente. Cada thread executa um loop:
Carregar partes na memória
Decida quais partes mesclar em seguida e carregue essas partes como blocos na memória.
Mesclar blocos
Mescle os blocos carregados na memória em um bloco maior.
Gravar no disco
Grave o bloco mesclado em uma nova parte no disco e retorne ao passo 1.
Observe que aumentar o número de núcleos de CPU e a quantidade de RAM aumenta o throughput das mesclas em segundo plano.
As partes que foram mescladas em partes maiores são marcadas como inativas e, por fim, excluídas após um número configurável de minutos. Com o tempo, isso cria uma árvore de partes mescladas (daí o nome da tabela MergeTree).
Paralelismo de inserção

Um servidor ClickHouse pode processar e inserir dados em paralelo. O nível de paralelismo de inserção afeta a taxa de ingestão e o uso de memória de um servidor ClickHouse. Carregar e processar dados em paralelo exige mais memória principal, mas aumenta a taxa de ingestão, já que os dados são processados mais rapidamente.
Funções de tabela como s3 permitem especificar conjuntos de nomes de arquivos a serem carregados por meio de padrões glob. Quando um padrão glob corresponde a vários arquivos existentes, o ClickHouse pode paralelizar as leituras entre esses arquivos e dentro de cada arquivo e inserir os dados em paralelo em uma tabela, utilizando threads de inserção executadas em paralelo (por servidor):

Até que todos os dados de todos os arquivos sejam processados, cada thread de inserção executa um loop:
① Get the next portion of unprocessed file data (portion size is based on the configured block size) and create an in-memory data block from it.
② Write the block into a new part on storage.
Go to ①. O número dessas threads paralelas de inserção pode ser configurado pela SETTING max_insert_threads. No ClickHouse de código aberto, o valor padrão desde a versão 26.8 é 0 (auto: o número de núcleos de CPU, reduzido sob pressão de memória). No ClickHouse Cloud, o padrão é 1 para nós com 8 GiB de memória, 2 para nós com 16 GiB e 4 para nós maiores.
Com um grande número de arquivos, o processamento paralelo por várias threads de inserção funciona bem. Ele pode saturar completamente tanto os núcleos de CPU disponíveis quanto a largura de banda da rede (para downloads paralelos de arquivos). Em cenários em que apenas alguns arquivos grandes serão carregados em uma tabela, o ClickHouse estabelece automaticamente um alto nível de paralelismo no processamento de dados e otimiza o uso da largura de banda da rede criando threads de leitura adicionais por thread de inserção para ler (baixar) em paralelo mais intervalos distintos dentro de arquivos grandes.
Para a função s3 e a tabela s3, o download paralelo de um arquivo individual é determinado pelos valores max_download_threads e max_download_buffer_size. Os arquivos só serão baixados em paralelo se o tamanho deles for maior que 2 * max_download_buffer_size. Por padrão, max_download_buffer_size é definido como 10MiB. Em alguns casos, você pode aumentar com segurança esse tamanho de buffer para 50 MB (max_download_buffer_size=52428800), com o objetivo de garantir que cada arquivo seja baixado por uma única thread. Isso pode reduzir o tempo que cada thread gasta fazendo chamadas ao S3 e, assim, também diminuir o tempo de espera no S3. Além disso, para arquivos pequenos demais para leitura paralela, o ClickHouse faz automaticamente a pré-busca de dados, pré-lendo esses arquivos de forma assíncrona para aumentar a taxa de transferência.
Medição de desempenho
Otimizar o desempenho das consultas que usam as funções de tabela do S3 é necessário tanto ao executar consultas diretamente sobre os dados — isto é, consultas ad hoc em que apenas o compute do ClickHouse é usado e os dados permanecem no S3 em seu formato original — quanto ao inserir dados do S3 em uma tabela com o motor de tabela MergeTree do ClickHouse. Salvo indicação em contrário, as recomendações a seguir se aplicam a ambos os cenários.
Impacto da capacidade do hardware

O número de núcleos de CPU disponíveis e a quantidade de RAM afetam:
- o tamanho inicial das partes suportado
- o nível possível de paralelismo de inserção
- a taxa de transferência das mesclagens de partes em segundo plano
e, portanto, a taxa geral de ingestão.
Localidade regional
Certifique-se de que seus buckets estejam na mesma região que suas instâncias do ClickHouse. Essa otimização simples pode melhorar drasticamente o throughput, especialmente se você implantar suas instâncias do ClickHouse na infraestrutura da AWS.
Formatos
O ClickHouse pode ler arquivos armazenados em buckets do S3 nos formatos compatíveis usando a função s3 e o engine S3. Ao ler arquivos brutos, alguns desses formatos têm vantagens específicas:
- Formatos com nomes de coluna codificados, como Native, Parquet, CSVWithNames e TabSeparatedWithNames, tornam as consultas menos verbosas, já que o usuário não precisa especificar o nome da coluna na função
s3. Os nomes das colunas permitem inferir essa informação. - Os formatos diferem em desempenho em termos de taxas de leitura e gravação. Native e Parquet são os formatos mais adequados para desempenho de leitura, pois já são orientados a colunas e mais compactos. O formato Native também se beneficia do alinhamento com a forma como o ClickHouse armazena dados na memória, reduzindo assim a sobrecarga de processamento à medida que os dados são transmitidos para o ClickHouse.
- O tamanho do bloco frequentemente afeta a latência das leituras em arquivos grandes. Isso fica muito evidente se você apenas amostrar os dados, por exemplo, retornando as N primeiras linhas. No caso de formatos como CSV e TSV, os arquivos precisam ser analisados para retornar um conjunto de linhas. Por isso, formatos como Native e Parquet permitem uma amostragem mais rápida.
- Cada formato de compressão traz prós e contras, geralmente equilibrando o nível de compressão e a velocidade, com ênfase no desempenho de compressão ou descompressão. Ao comprimir arquivos brutos como CSV ou TSV, o lz4 oferece o melhor desempenho de descompressão, em troca de um nível de compressão menor. O Gzip normalmente comprime melhor, à custa de velocidades de leitura um pouco mais lentas. O Xz leva isso ainda mais longe, geralmente oferecendo a melhor compressão, mas com o pior desempenho de compressão e descompressão. Ao exportar, Gz e lz4 oferecem velocidades de compressão comparáveis. Equilibre isso com a velocidade da sua conexão. Quaisquer ganhos com compressão ou descompressão mais rápidas serão facilmente anulados por uma conexão mais lenta com seus buckets do S3.
- Formatos como Native ou Parquet normalmente não justificam a sobrecarga da compressão. Qualquer redução no tamanho dos dados provavelmente será mínima, já que esses formatos são inerentemente compactos. O tempo gasto para comprimir e descomprimir raramente compensará o tempo de transferência pela rede, especialmente porque o S3 está disponível globalmente com maior largura de banda de rede.
Conjunto de dados de exemplo
Para ilustrar outras otimizações possíveis, usaremos os posts do conjunto de dados do Stack Overflow — otimizando tanto o desempenho das consultas quanto o das inserções desses dados.
Esse conjunto de dados consiste em 189 arquivos Parquet, um para cada mês entre julho de 2008 e março de 2024.
Observe que usamos Parquet por questões de desempenho, conforme nossas recomendações acima, executando todas as consultas em um cluster ClickHouse localizado na mesma região que o bucket. Esse cluster tem 3 nós, cada um com 32 GiB de RAM e 8 vCPUs.
Sem nenhum ajuste, demonstramos o desempenho da inserção desse conjunto de dados em um motor de tabela MergeTree, bem como da execução de uma consulta para identificar os usuários que fazem mais perguntas. Ambas as consultas exigem intencionalmente uma varredura completa dos dados.
-- Top usernames
SELECT
OwnerDisplayName,
count() AS num_posts
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN)
WHERE OwnerDisplayName NOT IN ('', 'anon')
GROUP BY OwnerDisplayName
ORDER BY num_posts DESC
LIMIT 5┌─OwnerDisplayName─┬─num_posts─┐
│ user330315 │ 10344 │
│ user4039065 │ 5316 │
│ user149341 │ 4102 │
│ user529758 │ 3700 │
│ user3559349 │ 3068 │
└──────────────────┴───────────┘
5 rows in set. Elapsed: 3.013 sec. Processed 59.82 million rows, 24.03 GB (19.86 million rows/s., 7.98 GB/s.)
Peak memory usage: 603.64 MiB.-- Load into posts table
INSERT INTO posts SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN)0 rows in set. Elapsed: 191.692 sec. Processed 59.82 million rows, 24.03 GB (312.06 thousand rows/s., 125.37 MB/s.)No nosso exemplo, retornamos apenas algumas linhas. Se estiver medindo o desempenho de consultas SELECT, em que grandes volumes de dados são retornados ao cliente, use o formato Null nas consultas ou direcione os resultados para o motor Null. Isso deve evitar que o cliente fique sobrecarregado com dados e que a rede fique saturada.
Usando threads para leituras
O desempenho de leitura no S3 aumentará linearmente com o número de núcleos, desde que você não esteja limitado pela largura de banda da rede ou pela E/S local. Aumentar o número de threads também gera variações de sobrecarga de memória das quais você deve estar ciente. Os itens a seguir podem ser ajustados para potencialmente melhorar o throughput de leitura:
- Em geral, o valor padrão de
max_threadsé suficiente, ou seja, o número de núcleos. Se a quantidade de memória usada por uma consulta for alta e precisar ser reduzida, ou se oLIMITdos resultados for baixo, esse valor pode ser diminuído. Usuários com bastante memória podem querer testar um aumento desse valor para obter maior throughput de leitura no S3. Normalmente, isso só traz benefício em máquinas com menos núcleos, ou seja, < 10. O ganho de paralelização adicional geralmente diminui à medida que outros recursos passam a ser gargalos, por exemplo, contenção de rede e CPU. - Versões do ClickHouse anteriores à 22.3.1 só paralelizavam leituras entre vários arquivos ao usar a função
s3ou o motor de tabelaS3. Isso exigia que o usuário garantisse que os arquivos fossem divididos em fragmentos no S3 e lidos usando um padrão glob para alcançar o melhor desempenho de leitura. Versões mais recentes agora paralelizam downloads dentro de um mesmo arquivo. - Em cenários com poucas threads, pode ser vantajoso definir
remote_filesystem_read_methodcomo "read" para fazer com que a leitura dos arquivos do S3 ocorra de forma síncrona. - Para a função
s3e a tabela, o download paralelo de um arquivo individual é determinado pelos valores demax_download_threadsemax_download_buffer_size. Emboramax_download_threadscontrole o número de threads usadas, os arquivos só serão baixados em paralelo se seu tamanho for maior que 2 *max_download_buffer_size. Por padrão,max_download_buffer_sizeé definido como 10MiB. Em alguns casos, você pode aumentar com segurança esse tamanho de buffer para 50 MB (max_download_buffer_size=52428800), com o objetivo de garantir que arquivos menores sejam baixados por apenas uma thread. Isso pode reduzir o tempo que cada thread gasta fazendo chamadas ao S3 e, assim, também diminuir o tempo de espera no S3. Veja esta postagem do blog para um exemplo disso.
Antes de fazer qualquer alteração para melhorar o desempenho, certifique-se de medir corretamente. Como as chamadas de API do S3 são sensíveis à latência e podem afetar os tempos do cliente, use o query log para acompanhar as métricas de desempenho, ou seja, system.query_log.
Considere nossa consulta anterior: dobrar max_threads para 16 (o padrão de max_thread é o número de núcleos em um nó) melhora em 2x o desempenho da nossa consulta de leitura, ao custo de maior uso de memória. Aumentar ainda mais max_threads traz ganhos decrescentes, como mostrado.
SELECT
OwnerDisplayName,
count() AS num_posts
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN)
WHERE OwnerDisplayName NOT IN ('', 'anon')
GROUP BY OwnerDisplayName
ORDER BY num_posts DESC
LIMIT 5
SETTINGS max_threads = 16┌─OwnerDisplayName─┬─num_posts─┐
│ user330315 │ 10344 │
│ user4039065 │ 5316 │
│ user149341 │ 4102 │
│ user529758 │ 3700 │
│ user3559349 │ 3068 │
└──────────────────┴───────────┘
5 rows in set. Elapsed: 1.505 sec. Processed 59.82 million rows, 24.03 GB (39.76 million rows/s., 15.97 GB/s.)
Peak memory usage: 178.58 MiB.SETTINGS max_threads = 325 rows in set. Elapsed: 0.779 sec. Processed 59.82 million rows, 24.03 GB (76.81 million rows/s., 30.86 GB/s.)
Peak memory usage: 369.20 MiB.SETTINGS max_threads = 645 rows in set. Elapsed: 0.674 sec. Processed 59.82 million rows, 24.03 GB (88.81 million rows/s., 35.68 GB/s.)
Peak memory usage: 639.99 MiB.Ajustando threads e o tamanho do bloco de inserção para inserts
Para alcançar o máximo desempenho de ingestão, você deve escolher (1) um tamanho do bloco de inserção e (2) um nível adequado de paralelismo de inserção com base em (3) a quantidade de núcleos de CPU e RAM disponíveis. Em resumo:
- Quanto maior configurarmos o tamanho do bloco de inserção, menos partes o ClickHouse terá de criar, e menos I/O de arquivos em disco e mesclagens em segundo plano serão necessários.
- Quanto maior configurarmos o número de threads paralelas de inserção, mais rapidamente os dados serão processados.
Há um trade-off entre esses dois fatores de desempenho (além do trade-off com a mesclagem de partes em segundo plano). A quantidade de memória principal disponível nos servidores ClickHouse é limitada. Blocos maiores usam mais memória principal, o que limita o número de threads paralelas de inserção que podemos utilizar. Por outro lado, um número maior de threads paralelas de inserção exige mais memória principal, já que o número de threads de inserção determina quantos blocos de insert são criados simultaneamente na memória. Isso limita o tamanho possível dos blocos de insert. Além disso, pode haver contenção de recursos entre threads de inserção e threads de merge em segundo plano. Um número alto de threads de inserção configuradas (1) cria mais partes que precisam ser mescladas e (2) consome núcleos de CPU e espaço de memória das threads de merge em segundo plano.
Para uma descrição detalhada de como o comportamento desses parâmetros afeta o desempenho e os recursos, recomendamos ler esta postagem do blog. Como descrito nessa postagem do blog, o ajuste pode exigir um equilíbrio cuidadoso entre os dois parâmetros. Esse teste exaustivo costuma ser impraticável, então, em resumo, recomendamos:
• max_insert_threads: choose ~ half of the available CPU cores for insert threads (to leave enough dedicated cores for background merges)
• peak_memory_usage_in_bytes: choose an intended peak memory usage; either all available RAM (if it is an isolated ingest) or half or less (to leave room for other concurrent tasks)
Then:
min_insert_block_size_bytes = peak_memory_usage_in_bytes / (~3 * max_insert_threads)Com esta fórmula, você pode definir min_insert_block_size_rows como 0 (para desativar o limite baseado em linhas), ao mesmo tempo em que define max_insert_threads com o valor escolhido e min_insert_block_size_bytes com o resultado calculado pela fórmula acima.
Usando esta fórmula com nosso exemplo anterior do Stack Overflow.
max_insert_threads=4(8 núcleos por nó)peak_memory_usage_in_bytes- 32 GiB (100% dos recursos do nó) ou34359738368bytes.min_insert_block_size_bytes=34359738368/(3*4) = 2863311530
INSERT INTO posts SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN) SETTINGS min_insert_block_size_rows=0, max_insert_threads=4, min_insert_block_size_bytes=28633115300 rows in set. Elapsed: 128.566 sec. Processed 59.82 million rows, 24.03 GB (465.28 thousand rows/s., 186.92 MB/s.)Como mostrado, o ajuste dessas configurações melhorou o desempenho de inserção em mais de 33%. Fica a cargo do leitor verificar se é possível melhorar ainda mais o desempenho em um único nó.
Escalonamento de recursos e nós
O escalonamento de recursos e nós se aplica tanto a consultas de leitura quanto a consultas de inserção.
Escalonamento vertical
Todos os ajustes e consultas anteriores usaram apenas um único nó no nosso cluster do ClickHouse Cloud. Também é comum haver mais de um nó do ClickHouse disponível. Recomendamos começar pelo escalonamento vertical, já que o throughput do S3 melhora linearmente com o número de núcleos. Se repetirmos nossas consultas anteriores de insert e leitura em um nó maior do ClickHouse Cloud, com o dobro dos recursos (64GiB, 16 vCPUs) e configurações apropriadas, ambas serão executadas em aproximadamente metade do tempo.
INSERT INTO posts SELECT *
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN) SETTINGS min_insert_block_size_rows=0, max_insert_threads=8, min_insert_block_size_bytes=28633115300 rows in set. Elapsed: 67.294 sec. Processed 59.82 million rows, 24.03 GB (888.93 thousand rows/s., 357.12 MB/s.)SELECT
OwnerDisplayName,
count() AS num_posts
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN)
WHERE OwnerDisplayName NOT IN ('', 'anon')
GROUP BY OwnerDisplayName
ORDER BY num_posts DESC
LIMIT 5
SETTINGS max_threads = 925 rows in set. Elapsed: 0.421 sec. Processed 59.82 million rows, 24.03 GB (142.08 million rows/s., 57.08 GB/s.)Escalonamento horizontal
Com o tempo, o escalonamento horizontal costuma se tornar necessário devido à disponibilidade de hardware e ao melhor custo-benefício. No ClickHouse Cloud, clusters de produção têm pelo menos 3 nós. Por isso, talvez você também queira utilizar todos os nós para uma inserção.
Utilizar um cluster para leituras do S3 exige o uso da função s3Cluster, conforme descrito em Utilizando clusters. Isso permite distribuir as leituras entre os nós.
O servidor que recebe inicialmente a consulta de inserção primeiro resolve o padrão glob e, em seguida, distribui dinamicamente o processamento de cada arquivo correspondente entre si e os outros servidores.

Repetimos nossa consulta de leitura anterior, distribuindo a carga de trabalho entre 3 nós e ajustando a consulta para usar s3Cluster. Isso é feito automaticamente no ClickHouse Cloud ao fazer referência ao cluster default.
Como observado em Utilizando clusters, esse trabalho é distribuído no nível dos arquivos. Para se beneficiar desse recurso, você precisará de um número suficiente de arquivos, ou seja, pelo menos > o número de nós.
SELECT
OwnerDisplayName,
count() AS num_posts
FROM s3Cluster('default', 'https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN)
WHERE OwnerDisplayName NOT IN ('', 'anon')
GROUP BY OwnerDisplayName
ORDER BY num_posts DESC
LIMIT 5
SETTINGS max_threads = 16┌─OwnerDisplayName─┬─num_posts─┐
│ user330315 │ 10344 │
│ user4039065 │ 5316 │
│ user149341 │ 4102 │
│ user529758 │ 3700 │
│ user3559349 │ 3068 │
└──────────────────┴───────────┘
5 rows in set. Elapsed: 0.622 sec. Processed 59.82 million rows, 24.03 GB (96.13 million rows/s., 38.62 GB/s.)
Peak memory usage: 176.74 MiB.Da mesma forma, nossa consulta INSERT pode ser distribuída, usando as configurações aprimoradas identificadas anteriormente para um único nó:
INSERT INTO posts SELECT *
FROM s3Cluster('default', 'https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN) SETTINGS min_insert_block_size_rows=0, max_insert_threads=4, min_insert_block_size_bytes=28633115300 rows in set. Elapsed: 171.202 sec. Processed 59.82 million rows, 24.03 GB (349.41 thousand rows/s., 140.37 MB/s.)Os leitores notarão que a leitura de arquivos melhorou o desempenho das consultas, mas não o das inserções. Por padrão, embora as leituras sejam distribuídas usando s3Cluster, as inserções ocorrerão no nó iniciador. Isso significa que, embora as leituras ocorram em cada nó, as linhas resultantes serão roteadas para o iniciador para distribuição. Em cenários de alta taxa de transferência, isso pode se tornar um gargalo. Para resolver isso, defina o parâmetro parallel_distributed_insert_select para a função s3cluster.
Definir isso como parallel_distributed_insert_select=2 garante que SELECT e INSERT sejam executados em cada shard, de/para a tabela subjacente da engine Distributed em cada nó.
INSERT INTO posts
SELECT *
FROM s3Cluster('default', 'https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN)
SETTINGS parallel_distributed_insert_select = 2, min_insert_block_size_rows=0, max_insert_threads=4, min_insert_block_size_bytes=28633115300 rows in set. Elapsed: 54.571 sec. Processed 59.82 million rows, 24.03 GB (1.10 million rows/s., 440.38 MB/s.)
Peak memory usage: 11.75 GiB.Como esperado, isso reduz o desempenho de inserção em 3 vezes.
Ajustes adicionais
Desativar a desduplicação
As operações de insert podem às vezes falhar devido a erros como timeout. Quando inserts falham, os dados podem ou não ter sido inseridos com sucesso. Para permitir que o cliente tente novamente os inserts com segurança, por padrão, em implantações distribuídas como o ClickHouse Cloud, o ClickHouse tenta determinar se os dados já foram inseridos com sucesso. Se os dados inseridos forem marcados como duplicados, o ClickHouse não os insere na tabela de destino. No entanto, o usuário ainda receberá um status de operação bem-sucedida, como se os dados tivessem sido inseridos normalmente.
Embora esse comportamento, que gera uma sobrecarga no insert, faça sentido ao carregar dados de um cliente ou em batches, ele pode ser desnecessário ao executar um INSERT INTO SELECT a partir do armazenamento de objetos. Ao desativar essa funcionalidade no momento do insert, podemos melhorar o desempenho, como mostrado abaixo:
INSERT INTO posts
SETTINGS parallel_distributed_insert_select = 2, min_insert_block_size_rows = 0, max_insert_threads = 4, min_insert_block_size_bytes = 2863311530, insert_deduplicate = 0
SELECT *
FROM s3Cluster('default', 'https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN)
SETTINGS parallel_distributed_insert_select = 2, min_insert_block_size_rows = 0, max_insert_threads = 4, min_insert_block_size_bytes = 2863311530, insert_deduplicate = 00 rows in set. Elapsed: 52.992 sec. Processed 59.82 million rows, 24.03 GB (1.13 million rows/s., 453.50 MB/s.)
Peak memory usage: 26.57 GiB.Otimização na inserção
No ClickHouse, a configuração optimize_on_insert controla se as partes de dados são mescladas durante o processo de inserção. Quando está habilitada (optimize_on_insert = 1 por padrão), partes pequenas são mescladas em partes maiores à medida que são inseridas, melhorando o desempenho das consultas ao reduzir o número de partes que precisam ser lidas. No entanto, essa mesclagem adiciona sobrecarga ao processo de inserção, o que pode deixar inserções com alta vazão mais lentas.
Desabilitar essa configuração (optimize_on_insert = 0) faz com que a mesclagem durante as inserções seja ignorada, permitindo que os dados sejam gravados mais rapidamente, especialmente ao lidar com inserções pequenas e frequentes. O processo de mesclagem é adiado para segundo plano, permitindo melhor desempenho de inserção, mas aumentando temporariamente o número de partes pequenas, o que pode deixar as consultas mais lentas até que a mesclagem em segundo plano seja concluída. Essa configuração é ideal quando o desempenho de inserção é prioridade e o processo de mesclagem em segundo plano pode cuidar da otimização de forma eficiente depois. Como mostrado abaixo, desabilitar essa configuração pode melhorar a vazão de inserção:
SELECT *
FROM s3Cluster('default', 'https://datasets-documentation.s3.eu-west-3.amazonaws.com/stackoverflow/parquet/posts/by_month/*.parquet', NOSIGN)
SETTINGS parallel_distributed_insert_select = 2, min_insert_block_size_rows = 0, max_insert_threads = 4, min_insert_block_size_bytes = 2863311530, insert_deduplicate = 0, optimize_on_insert = 00 rows in set. Elapsed: 49.688 sec. Processed 59.82 million rows, 24.03 GB (1.20 million rows/s., 483.66 MB/s.)Notas diversas
- Em cenários com pouca memória, considere reduzir
max_insert_delayed_streams_for_parallel_writese estiver inserindo no S3.