INSERT ... VALUES simples que pode passar pela fila de insert assíncrono: um INSERT ... SELECT também pode. Esta página descreve quando isso acontece, como o lado de escrita é contabilizado e o que ocorre quando a consulta é cancelada ou atinge o tempo limite.
Elegibilidade e roteamento
UmINSERT ... SELECT segue a rota da fila assíncrona somente quando todas estas condições são atendidas:
async_insert = 1.async_insert_select_as_async_insert = 1(o padrão). Esta é a chave geral: com ela desativada,INSERT ... SELECTé sempre síncrono, independentemente deasync_insert. Definircompatibilitypara uma versão anterior à 26.10 muda seu padrão para0; definir explicitamenteasync_insert_select_as_async_insert = 1reativa o comportamento.- O resultado inteiro do
SELECTcabe em um único bloco de tamanho não superior aasync_insert_max_data_size. - O destino é uma tabela da família
MergeTree(nesta verificação, um alias é resolvido até a tabela a que se refere).
- O resultado abrange mais de um bloco, excede
async_insert_max_data_sizeou está vazio. - É usado quórum não paralelo:
insert_quorumestá definido einsert_quorum_parallel = 0. - O destino possui visões materializadas dependentes.
- O destino é uma visão materializada. A verificação de
MergeTreese aplica à visão, e não à sua tabela de destino, portanto ela não é elegível. - O destino é uma função de tabela ou um motor de tabela remoto, como
Distributed. - O
SELECTlê sua própria tabela de destino (INSERT INTO t SELECT ... FROM t). insert_null_as_defaultprecisa substituir por um valor padrão os dados de uma colunaNullabledoSELECTque alimenta uma coluna de destino nãoNullable.- O insert é interno (atualização de view materializada atualizável,
POPULATEouCREATE TABLE ... AS SELECT). Esses casos são sempre síncronos e ignoramasync_insert_select_as_async_inserteasync_insert.
implicit_transaction = 1), a rota assíncrona não tem suporte e, por padrão, o ClickHouse gera NOT_IMPLEMENTED em vez de voltar para a rota síncrona. Somente com throw_on_unsupported_query_inside_transaction = 0 a consulta passa a ser executada como um insert síncrono.
O roteamento definido antes da verificação assíncrona tem precedência, de modo que o próprio SELECT pode, por si só, descartar a rota assíncrona. Com parallel_distributed_insert_select (ativado por padrão), um INSERT ... SELECT que lê de uma fonte em cluster, como s3Cluster, e grava em uma tabela replicada é executado pelo caminho de insert distribuído e nunca chega à fila assíncrona. O mesmo ocorre com réplicas paralelas.
Modo de retorno e espera
wait_for_async_insert funciona como em qualquer inserção assíncrona: 1 (o padrão) aguarda o flush; 0 retorna assim que o bloco entra na fila.
Para ajudar um SELECT a gerar o bloco único exigido pela rota assíncrona: optimize_trivial_insert_select limita um INSERT INTO dest SELECT ... FROM source trivial entre tabelas distintas a max_insert_threads threads de leitura. Com max_insert_threads = 1, o SELECT normalmente gera um único bloco.
Contabilização de gravações e observabilidade
A gravação é atribuída à consulta de flush, e não aoINSERT ... SELECT original:
- A consulta de flush é dona dos
ProfileEventsde gravação (InsertedRows,InsertedBytes) e recebe sua própria linha de gravação emsystem.query_log. Na linha doINSERT ... SELECToriginal, essesProfileEventsaparecem com valor0. Para ver os números de gravação do próprio flush, consulte a linha correspondente emsystem.query_logesystem.asynchronous_insert_log. - Com
wait_for_async_insert = 1(o padrão), os valoreswritten_rowsewritten_bytesda própria consulta (e o cabeçalho HTTPX-ClickHouse-Summary) informam as linhas e os bytes aceitos doSELECT, e não o total da própria consulta de flush. Uma falha no flush continua sendo reportada como erro ao cliente. - Com
wait_for_async_insert = 0, esses números não são informados, pois a consulta retorna antes que o resultado do flush esteja disponível. - A cota
WRITTEN_BYTESé cobrada uma única vez, no caminho do flush, e não é revertida caso o flush falhe.
Cancelamento e tempos limite
O bloco é enfileirado antes de começar a espera pelo flush; portanto, cancelar a consulta apenas faz o cliente parar de esperar, mas não impede que a fila seja descarregada.KILL QUERY, ou atingirmax_execution_timedurante a espera, retorna um erro ao cliente, mas as linhas ainda podem ser gravadas. Não considere uma consulta cancelada ou que excedeu o tempo limite nesse caminho como prova de que nada foi gravado.- Com
timeout_overflow_mode = 'break', não há erro nem retorno antecipado: a consulta aguarda o flush além demax_execution_time, atéwait_for_async_insert_timeout. Interromper a espera antecipadamente reportaria sucesso antes de a gravação ser confirmada.
Quando as decisões são definidas
A elegibilidade para a rota assíncrona é decidida uma única vez, no início da consulta e antes de o bloco ser enfileirado. Além disso, uma verificação de acesso antecipada rejeita logo de início um insert não autorizado. Se umINSERT ... SELECT segue ou não a rota assíncrona depende do formato do bloco do resultado, e não apenas de async_insert.
Em seguida, a busca do destino e a verificação de autorização definitiva são executadas no momento do flush, assim como em qualquer insert assíncrono. Portanto, se uma visão materializada for anexada ao destino ou uma concessão for revogada entre o enfileiramento e o flush, isso afetará o flush.