Não é recomendável enviar muitos batches pequenos no modo síncrono, pois isso leva à criação de muitas partes. Isso resultará em baixo desempenho de consulta e em erros de “too many part”.
async_insert.
As inserções assíncronas têm suporte nas interfaces HTTP e TCP nativo.
Quando habilitadas (async_insert = 1), as inserções são mantidas em buffer e gravadas em disco somente quando uma das condições de flush é atendida:
- O buffer atinge um tamanho de dados especificado (
async_insert_max_data_size, padrão de 100 MiB). - Um limite de tempo é atingido (
async_insert_busy_timeout_ms, padrão de 200 ms ou 1000 ms no Cloud). - Um número máximo de consultas de insert é acumulado (
async_insert_max_query_number, padrão de 450).
Escolhendo um modo de retorno
wait_for_async_insert.
Quando definida como 1 (o padrão), o ClickHouse só confirma a inserção depois que os dados são gravados com sucesso em disco. Isso garante fortes garantias de durabilidade e torna o tratamento de erros simples: se algo der errado durante o flush, o erro é retornado ao cliente. Esse modo é recomendado para a maioria dos cenários de produção, especialmente quando falhas de inserção precisam ser rastreadas com confiabilidade.
Benchmarks mostram que isso escala bem com a concorrência — esteja você executando 200 ou 500 clientes — graças às inserções adaptativas e ao comportamento estável na criação de partes.
Definir wait_for_async_insert = 0 habilita o modo “fire-and-forget”. Nesse caso, o servidor confirma a inserção assim que os dados são colocados no buffer, sem esperar que cheguem ao armazenamento.
Isso oferece inserções com latência ultrabaixa e throughput máximo, ideal para dados de alta velocidade e baixa criticidade. No entanto, isso traz desvantagens: não há garantia de que os dados serão persistidos, os erros só aparecem durante o flush, e não há fila de dead-letter para inserções com falha — rastrear falhas exige inspecionar os logs do servidor e as tabelas do sistema posteriormente. Use esse modo apenas se o seu workload puder tolerar perda de dados.
Benchmarks também demonstram redução substancial de partes e menor uso de CPU quando os flushes do buffer são pouco frequentes (por exemplo, a cada 30 segundos), mas o risco de falha silenciosa permanece.
Nossa recomendação enfática é usar async_insert=1,wait_for_async_insert=1 ao usar inserções assíncronas. Usar wait_for_async_insert=0 é muito arriscado porque seu cliente de INSERT pode não perceber se houver erros, e também pode causar uma possível sobrecarga se o cliente continuar gravando rapidamente em uma situação em que o servidor ClickHouse precise desacelerar as gravações e criar alguma contrapressão para garantir a confiabilidade do serviço.
Inserts assíncronos adaptativos
async_insert_use_adaptive_busy_timeout). Em vez de um intervalo de flush fixo, o timeout se ajusta dinamicamente entre um mínimo (async_insert_busy_timeout_min_ms, padrão de 50 ms) e um máximo (async_insert_busy_timeout_max_ms, padrão de 200 ms ou 1000 ms no Cloud), com base na taxa de chegada dos dados.
Quando os dados chegam com frequência, o timeout fica mais próximo do mínimo para fazer o flush mais cedo e reduzir a latência de ponta a ponta. Quando os dados são esparsos, ele aumenta em direção ao máximo para acumular lotes maiores. Isso é especialmente útil no modo padrão (wait_for_async_insert=1), em que um timeout fixo alto faria os clientes ficarem bloqueados durante todo o intervalo, mesmo quando os dados já estivessem prontos para flush.
Tratamento de erros
wait_for_async_insert=1), o erro é retornado ao cliente. No modo fire-and-forget, os erros são gravados nos logs do servidor e na tabela system.asynchronous_inserts.
Cada flush cria pelo menos uma parte para cada valor distinto da chave de particionamento no buffer. Mesmo em tabelas sem chave de particionamento, um único flush pode produzir várias partes se os dados em buffer excederem max_insert_block_size (padrão: ~1 milhão de linhas).
Apesar de usar async inserts, você ainda pode encontrar erros de “too many parts” se a chave de particionamento tiver alta cardinalidade.
Desduplicação e confiabilidade
Habilitando inserções assíncronas
-
Habilite as inserções assíncronas no nível do usuário. Este exemplo usa o usuário
default; se você criar outro usuário, substitua pelo respectivo nome de usuário: -
Você pode especificar as configurações de inserção assíncrona usando a cláusula SETTINGS nas consultas de inserção:
-
Você também pode especificar as configurações de inserção assíncrona como parâmetros de conexão ao usar um cliente ClickHouse de uma linguagem de programação.
Por exemplo, veja como fazer isso em uma string de conexão JDBC ao usar o driver JDBC Java do ClickHouse para se conectar ao ClickHouse Cloud:
As inserções assíncronas não se aplicam a consultas
INSERT INTO ... SELECT. Quando a inserção contém uma cláusula SELECT, a consulta é sempre executada de forma síncrona, independentemente da configuração async_insert.Esvaziando os buffers ao encerrar
Comparação com tabelas Buffer
- Nenhuma alteração de DDL é necessária. As inserções assíncronas são transparentes — você habilita uma configuração, sem criar tabelas adicionais.
- Buffer por formato de consulta. As inserções assíncronas mantêm buffers separados para cada combinação única de formato de consulta e configurações, permitindo políticas de flush mais granulares. As tabelas Buffer usam um único buffer por tabela de destino.
- Durabilidade. No modo padrão (
wait_for_async_insert=1), os dados são confirmados em disco antes de o cliente receber a confirmação. As tabelas Buffer funcionam no estilo fire-and-forget — os dados em buffer são perdidos em caso de falha. - Comportamento em cluster. Em clusters, os buffers de inserção assíncrona são mantidos por nó. As tabelas Buffer exigem criação explícita em cada nó.