INSERT, telemetria de execução e sinais de erro. É o protocolo usado pelo cliente de linha de comando, pelo driver nativo em C++ e pela maioria dos drivers nativos de terceiros.
Esta página aborda o protocolo em si: estruturação de pacotes, a máquina de estados da conexão, negociação de versão e o corpo de todas as mensagens que não sejam Block. Os bytes dentro dos pacotes da família Data (o Block, suas colunas e as codificações por tipo) são um assunto à parte, documentado na especificação de Formato Nativo.
Especificação complementarEsta página faz par com a especificação complementar de Formato Nativo e é publicada junto com ela. As duas especificações dividem o trabalho de forma clara: esta página cobre a camada de pacotes e transporte; a especificação de Formato Nativo cobre os bytes dentro dos pacotes da família
Data.BlockInfo, portanto um único byte fora do lugar dessincroniza tudo o que vem a seguir. Ele é com estado, e cada conexão TCP processa uma consulta por vez — não há multiplexação. Inteiros de largura fixa são codificados em little-endian.
Visão geral
Cada mensagem no wire começa com um código de tipo de pacote
VarUInt, seguido de um corpo cuja estrutura depende desse código e da versão negociada do protocolo.
Uma conexão passa por três fases — um handshake único, depois qualquer número de trocas Ping ou Query e, por fim, o encerramento:
O protocolo TCP nativo sempre transporta dados tabulares no formato Native, independentemente de qualquer cláusula FORMAT no SQL. Reformatar para RowBinary, CSV, JSON e assim por diante é tarefa do cliente, feita depois que ele decodifica os blocos Native. (A interface HTTP segue um caminho de código diferente e de fato respeita a cláusula FORMAT; HTTP está fora do escopo aqui.)
Segurança
Segurança de transporte (TLS)
Autenticação
ClientHello. Os campos user e password são transmitidos como strings em texto simples, portanto a criptografia na camada de transporte (TLS) é a responsável por proteger as credenciais em trânsito.
A autenticação SSH por challenge-response está disponível a partir da versão 54466 do protocolo — consulte autenticação SSH por challenge-response.
Segredo entre servidores
auth_hash SHA-256 de 32 bytes no campo 4 de Query, calculado a partir de um salt, um nonce, do segredo configurado e da consulta; o servidor receptor o recalcula e o compara. Isso é controlado pelo recurso INTERSERVER_SECRET (v54441). Clientes externos sempre enviam uma string vazia aqui. Consulte Autenticação entre servidores.
Versionamento e feature gates
Negociação de versão
Feature gates
Tabela de funcionalidades
Encapsulamento do pacote
VarUInt, não um byte de largura fixa. Para valores abaixo de 128, um VarUInt produz o mesmo único byte, mas as implementações devem usar a codificação VarUInt para permanecer compatíveis caso tipos de pacote futuros cheguem a 128 ou mais.
A referência de mensagens documenta apenas o corpo de cada pacote — os bytes após o código do tipo de pacote. A numeração dos campos começa em 1, com o primeiro campo do corpo.
Enquadramento em fragmentos (v54470+)
CHUNKED_PROTOCOL é negociado (consulte o handshake), cada pacote no wire é envolvido por um enquadramento em fragmentos. Esse encapsulamento é por direção: cliente→servidor e servidor→cliente são negociados separadamente e podem acabar em modos diferentes (em fragmentos versus sem enquadramento).
Layout no wire de cada pacote:
VarUInt está dentro do fluxo em fragmentos: ele é o primeiro byte do payload do pacote (o primeiro byte do primeiro fragmento), não um byte separado enviado antes do framing. O payload em fragmentos de cada pacote é o [VarUInt packet_type_code][message body] completo do envelope do pacote. Um cliente que deixa o tipo de pacote fora do fluxo em fragmentos faz com que a outra ponta leia esse byte de tipo como o primeiro byte do tamanho do fragmento u32, dessincronizando a conexão.
Um único pacote pode ser dividido em vários fragmentos se o buffer do gravador encher no meio do pacote; uma divisão pode ocorrer em qualquer ponto, inclusive dentro do VarUInt do tipo de pacote. O leitor concatena os payloads dos fragmentos e trata o zero final de 4 bytes como um limite de pacote transparente — ele o consome, mas não o expõe ao que estiver lendo os corpos dos pacotes.
Pacotes sem corpo ainda são encapsulados: um pacote de um único byte, como Ping ou Pong, torna-se [u32 size = 1][0x04][u32 0] assim que o envio em fragmentos é negociado. Qualquer descrição de “byte único no wire” em outro ponto desta página se refere à forma anterior ao envio em fragmentos.
Negociação. ServerHello e Addendum carregam, cada um, dois campos String, um por direção, com valores de {"chunked", "notchunked", "chunked_optional", "notchunked_optional"}:
chunked/notchunkedsão estritos: esse lado exige exatamente esse modo.- As variantes
_optionalsão flexíveis: aceitam qualquer modo que o outro lado escolher.
No lado do cliente, a preferência de ENVIO do cliente é negociada com a preferência de RECEBIMENTO do servidor, e vice-versa.
Temporização. As strings de negociação trafegam no wire sem framing: ClientHello → ServerHello (preferências do servidor) → Addendum (valores negociados do cliente). A mudança de framing se aplica a cada byte enviado depois que o Addendum é descarregado do buffer. O próprio Addendum, o ClientHello e o ServerHello nunca usam framing.
Ciclo de vida da conexão
HANDSHAKE, READY, READING_RESPONSE ou encerrada. Como o protocolo não oferece multiplexação, um cliente que envia uma nova solicitação antes de consumir totalmente a resposta anterior intercala bytes no wire e corrompe o fluxo.
Estados
HANDSHAKE → READY → READING_RESPONSE → READY — com o loop de Ping/Pong e todas as transições de falha convergindo para o único sink Terminated.
Fase de handshake
-
O cliente envia
ClientHellocom a versão máxima de protocolo compatível. -
O cliente lê a resposta e a encaminha de acordo com o tipo de pacote:
-
Se
negotiated_version ≥ 54458(o recursoADDENDUM), o cliente envia umAddendum. Essa decisão se baseia na versão negociada, não na versão declarada pelo cliente.
READY; em caso de erro, ela é encerrada.
Fase de Ping
READY, o fluxo é:
-
O cliente envia
Ping. -
O cliente lê a resposta:
Fase da consulta
EndOfStream ou Exception.
Partindo de READY, o fluxo é:
Em caso de erro em qualquer ponto, o servidor envia uma Exception em vez de EndOfStream, o que encerra a consulta.
-
O cliente envia
Querycom umquery_idexclusivo (normalmente um UUID). -
O cliente envia quaisquer tabelas externas e, em seguida, o marcador
Datavazio. O pacoteDatavazio temtable_name = "",num_columns = 0,num_rows = 0. O servidor não começa a executar a consulta até receber esse marcador. -
O cliente passa para
READING_RESPONSEe faz flush do buffer de escrita. -
O cliente lê os pacotes de resposta em loop, despachando por tipo:
EndOfStream ou em uma Exception tratada, a conexão retorna para READY. Uma violação de protocolo ou erro de E/S a encerra.
O caso
num_rows == 0 costuma confundir novas implementações. Um bloco com zero linhas é um marcador de limite ou um cabeçalho de esquema, não um sinal de fim de stream. Somente EndOfStream ou Exception encerra a resposta.Fase INSERT
INSERT; o servidor responde com um bloco de esquema que descreve a tabela de destino; o cliente transmite pacotes Data com as linhas e, em seguida, o marcador Data vazio; o servidor finaliza com EndOfStream ou Exception.
Partindo de READY, o SQL é um INSERT no formato INSERT INTO <table> [(<cols>)] VALUES — sem um literal VALUES (...) embutido, já que os dados das linhas fluem por meio de pacotes Data. O fluxo:
- O cliente envia
Querycombodydefinido como o SQL de INSERT. - O cliente envia quaisquer tabelas externas (raro em INSERT). Diferentemente da fase de consulta, ele não envia aqui um marcador Data vazio. O pacote
QuerydeINSERTé enviado com dados pendentes, portanto o bloco vazio de fim de dados é adiado para a etapa 5; enviá-lo antes do bloco de esquema faria o servidor interpretá-lo como o fim do stream de linhas, concluir o INSERT sem linhas e então analisar o primeiro pacote de linha real como um pacote avulso de nível superior. - O cliente drena os pacotes de metadados (TableColumns, Progress, ProfileInfo, Log, ProfileEvents) até ler o pacote Data de esquema — um Block com 0 linhas, mas com a estrutura completa das colunas (nomes e tipos). O bloco de esquema é o contrato: as linhas que o cliente envia em seguida devem corresponder a essas estruturas de coluna.
- O cliente envia bloco(s) de dados. Para cada bloco, ele grava
VarUInt(ClientPacket::Data = 2), depoisString("")para o nome vazio da tabela externa, e então o Block. Os tipos das colunas devem corresponder, por posição, às colunas do bloco de esquema. - O cliente envia o terminador de fim de entrada: um pacote Data com um Block vazio (0 colunas, 0 linhas).
- O cliente drena o stream de resposta até
EndOfStream(sucesso) ouException(falha).
async_insert = 1, o servidor enfileira as linhas e faz o flush delas como parte de um batch. Na versão negociada ≥ 54484 (PROGRESS_IN_ASYNC_INSERT), assim que o flush é concluído, o servidor emite um pacote extra de Progress, imediatamente seguido pelos ProfileEvents do insert e então por EndOfStream. Abaixo de 54484, o servidor omite esse Progress final. O pacote é um Progress comum; como o servidor redefine o pipeline da consulta antes de incorporar as contagens de escrita, na prática o incremento carrega apenas o tempo decorrido, e as estatísticas de linhas e bytes gravados chegam ao cliente por meio dos ProfileEvents correspondentes. Um cliente que já drena pacotes Progress intercalados na etapa 6 só precisa aceitar mais um pacote.
A conexão retorna para READY em EndOfStream ou em uma Exception tratada. Violações de protocolo e erros de E/S a encerram.
Referência de mensagens
Type usa:
VarUInt— inteiro sem sinal de comprimento variável (consulte VarUInt).String— bytes com prefixo VarUInt (consulte String).UInt8,Int32e assim por diante — inteiros little-endian de largura fixa.Bool— um único byte,0x00ou0x01.
Role indica quem usa cada campo:
- client — definido por clientes externos.
- inter-server — relevante apenas para a comunicação entre servidores; clientes externos gravam um valor padrão.
- universal — usado por ambos.
ClientHello (tipo de pacote 0)
ServerHello (tipo de pacote 0)
Rule — um elemento de
password_complexity_rules:
A lista reflete a configuração da política de senhas do operador do servidor e é puramente consultiva — o servidor não aplica essas regras durante o handshake. Um cliente que exponha funcionalidade de alteração/definição de senha pode usar as regras para sinalizar erros antes de fazer o round-trip de uma senha incompatível até o servidor.
Para limitar o uso de recursos diante de um servidor hostil ou mal configurado, limite o
count decodificado a 256 entradas e cada String pattern e message a 4096 bytes. Um count de 0 (sem pares subsequentes) é o caso comum para servidores sem política de senhas configurada.Adendo (sem tipo de pacote)
ADDENDUM (v54458). Enviado imediatamente após a conclusão da troca de handshake. Não é um tipo de pacote distinto — os campos vão pelo wire em bruto, sem prefixo de byte de tipo de pacote.
A mudança para o enquadramento chunked se aplica depois que este Adendo é enviado — o próprio Adendo não tem enquadramento.
Ping (tipo de pacote 4)
0x04 antes do enquadramento por fragmentos; quando o uso de fragmentos é negociado, o byte passa a ser o payload de um byte de um fragmento (consulte enquadramento por fragmentos).
Pong (tipo de pacote 4)
0x04 antes do enquadramento por fragmentos; quando a fragmentação é negociada, o byte se torna o payload de um byte de um fragmento (consulte enquadramento por fragmentos).
Exception (tipo de pacote 2)
Consulta (tipo de pacote 1)
ClientInfo (embutido em consulta)
CLIENT_INFO (v54032). (Alguns campos dentro de ClientInfo são condicionados a versões posteriores, como indicado abaixo em cada campo.)
Layout dependente da interface (campos 7–12)Os campos 7–12 acima correspondem ao ramo TCP. Quando
query_interface (campo 6) não é TCP, esses campos são substituídos por um layout de wire diferente — não se trata apenas de omissões opcionais, portanto um decodificador deve seguir o ramo com base no campo 6.query_interface = 2(HTTP): nesse caso, são gravadas as informações da requisição HTTP encaminhada pelo servidor —http_method(UInt8),http_user_agent(String), depoisforwarded_for(String, condicionado aX_FORWARDED_FOR_IN_CLIENT_INFOv54443) ehttp_referer(String, condicionado aREFERER_IN_CLIENT_INFOv54447). Os camposos_user/client_hostname/client_name/version_*/protocol_versionnão estão presentes.- Qualquer outra interface: nenhum dos campos TCP (7–12) nem dos campos HTTP é gravado; o fluxo segue diretamente para
quota_key.
quota_key (campo 13) e distributed_depth (campo 14) vêm em seguida para todas as interfaces, e version_patch (campo 15) é gravado apenas para TCP.Esse ramo importa principalmente para o tráfego entre servidores, quando o servidor de origem encaminha uma consulta que chegou originalmente por HTTP. Um decodificador que sempre ler os campos TCP interpretará esses pacotes de forma incorreta — tratando http_method ou http_user_agent como quota_key.Autenticação entre servidores
auth_hash) não é o segredo compartilhado do cluster no wire. Enviar o segredo puro faria a autenticação falhar e ainda o exporia. Em vez disso, um servidor atuando como cliente interservidor prova que conhece o segredo com um hash SHA-256 com salt:
- Entre no modo interservidor. O servidor que está se conectando sinaliza isso em
ClientHello: o campouseré o marcador interservidor epasswordfica vazio. Em seguida, ele acrescenta mais duas strings — o nome do cluster e umsaltde 32 bytes recém-gerado (encodeSHA256de um valor aleatório) — imediatamente após os camposuser/password, como parte do mesmo pacoteClientHello. O servidor lê essas duas strings antes de enviarServerHello, então o cliente precisa escrevê-las logo de saída; esperar primeiro porServerHellocausa deadlock, porque o servidor fica bloqueado tentando lê-las. - Obtenha o nonce.
ServerHellotraz um nonceUInt64de 8 bytes quandoINTERSERVER_SECRET_V2(v54462) é negociado. - Calcule o hash. Para cada pacote de consulta que não seja
InitialQuery, o cliente escreveencodeSHA256(salt + nonce + cluster_secret + query + query_id + initial_user + external_roles)no campo 4 — um digest de 32 bytes. (nonceusa sua forma de string decimal, presente somente quando negociado ≥ v54462;external_rolesé acrescentado somente quandoINTERSERVER_EXTERNALLY_GRANTED_ROLES(v54472) é negociado.) Para umInitialQuery, ou quando nenhum segredo de cluster está configurado, o cliente escreve uma string vazia. - Verifique. O servidor lê o campo 4 com um limite de 32 bytes e recompõe a mesma concatenação usando sua própria cópia do segredo do cluster; a conexão é rejeitada se os digests forem diferentes.
auth_hash vazio.
SETTING
key vazia — um único VarUInt 0, sem flags nem value em seguida. Apenas a codificação de cada configuração depende da versão negociada, condicionada por SETTINGS_SERIALIZED_AS_STRINGS (v54429).
v54429+ (STRINGS_WITH_FLAGS) — cada configuração é a tripla mostrada aqui:
Os campos 2 e 3 ficam ausentes quando
key está vazia.
Pré-54429 (BINARY) — cada configuração é [String key][type-specific binary value]: o campo flags não é gravado, e o valor é codificado na forma binária nativa da configuração (por exemplo, um inteiro de largura fixa ou uma string com prefixo de comprimento), em vez de como uma string decimal/textual. A lista continua sendo terminada por uma key vazia. Um cliente que tenha como alvo uma versão negociada inferior a 54429 deve ler e gravar essa forma binária, não a tripla acima. (As configurações personalizadas definidas pelo usuário são a exceção: elas sempre incluem flags e um valor em string, em ambas as codificações.)
O campo flags agrupa:
0x01— Important: a configuração afeta os resultados da consulta e não deve ser ignorada silenciosamente por pares mais antigos.0x02— Custom: uma custom setting definida pelo usuário.0x0c— um campo de tier de 2 bits, não uma flag independente:0x00= Production,0x04= Obsolete,0x08= Experimental,0x0c= Beta. Leia os 2 bits completos (flags & 0x0c) — um teste ingênuo comflags & 0x04classificaria Beta (0x0c) incorretamente como Obsolete.0x80— HotReload (recarregamento de config sem reinicialização; definido no enum de flags, encontrado principalmente em configurações de coordination).
Parâmetro
SELECT {x:UInt64}. Codificados exatamente como uma SETTING, com o sinalizador Custom (0x02) ativado, e encerrados da mesma forma, por uma chave vazia.
O valor do parâmetro é a representação SQL do valor, não um literal bruto. Parâmetros do tipo string devem ser passados já entre aspas simples (por exemplo, o valor de
{name:String} é 'Alice', não Alice); caso contrário, o analisador de valores do servidor os rejeitará.Data (tipo de pacote 1 servidor→cliente, tipo de pacote 2 cliente→servidor)
table_name antes do Block. Apenas o byte do tipo de pacote difere.
O marcador de fim de dados é um pacote cujo Block está vazio —
0 colunas e 0 linhas — independentemente de table_name. O servidor trata um pacote Data do cliente como terminador apenas quando o bloco decodificado está vazio (block.empty()); um pacote com table_name = "" e um bloco não vazio é um pacote comum de linhas, não um terminador. Portanto, um fluxo de linhas de INSERT é uma sequência de blocos Data não vazios, seguida por um bloco Data vazio que o encerra.
As variantes de bloco e seus significados estão documentados em Block variants.
Progress (tipo de pacote 3)
Progress anterior, não totais acumulados. Antes de enviar, o servidor lê seus contadores, reinicia-os atomicamente para zero e calcula elapsed_ns como o delta de tempo desde o último envio. Portanto, um cliente deve acumular os pacotes sucessivos localmente para obter totais correntes — tratar um pacote como um valor absoluto faz a exibição do progresso retroceder ou subestimar a contagem quando mais de um pacote chega.
ProfileInfo (tipo de pacote 6)
Totais (tipo de pacote 7)
WITH TOTALS. O formato wire é idêntico a Data: uma string table_name (sempre vazia), seguida por um Block. Apenas o byte do tipo de pacote difere.
Extremes (tipo de pacote 8)
extremes está ativada. O formato wire é idêntico a Data. O bloco tem exatamente 2 linhas: a linha 0 contém o mínimo de cada coluna, e a linha 1 contém o máximo.
Log (tipo de pacote 10)
send_logs_level; consulte streaming de logs).
Mesmo formato de envelope e corpo que Data. O bloco tem num_columns = 8 fixo e um esquema predefinido. Cada linha de log corresponde a uma linha nas 8 colunas, e um único pacote Log pode carregar muitas linhas.
ProfileEvents (tipo de pacote 14)
num_columns = 6 fixo e um esquema predefinido. Cada evento corresponde a uma linha.
O tipo de elemento da coluna
value não é fixo de um pacote para outro — servidores mais antigos emitem UInt64, e os mais novos, Int64. Leia a string de tipo da coluna no cabeçalho do bloco, em vez de presumir um tamanho fixo.TableColumns (tipo de pacote 11)
COLUMN_DEFAULTS_METADATA (v54410). O servidor o envia antes do bloco de esquema do INSERT para carregar os metadados de valores padrão das colunas, mas apenas quando a versão negociada é ≥ 54410 e a configuração input_format_defaults_for_omitted_fields está habilitada. Abaixo de 54410, o pacote nunca é enviado, portanto um cliente mais antigo não deve esperar por ele — o bloco de esquema Data vem diretamente. Um cliente v54410+ deve estar preparado para qualquer uma das ordens: um TableColumns opcional, seguido pelo bloco de esquema.
Corpo comprimido a partir da v54481Na versão negociada ≥ 54481 (
COMPRESSED_LOGS_PROFILE_EVENTS_COLUMNS), o servidor grava ambos os campos pelo mesmo caminho de saída opcionalmente comprimido; portanto, quando a consulta tem compression = true, todo o corpo de TableColumns (external_table + columns_description) fica dentro do frame de compressão, e o cliente o lê pelo fluxo descomprimido correspondente. Quando a consulta não tem compressão, o corpo vai pela wire sem compressão, exatamente como a tabela acima mostra. Isso é importante para respostas de esquema de INSERT: um cliente que altere o tratamento de compressão para Log e ProfileEvents, mas não para TableColumns, lerá a resposta incorretamente quando a compressão da consulta estiver habilitada.TimezoneUpdate (tipo de pacote 17)
TIMEZONE_UPDATES (v54464). Enviado em exatamente um lugar: no inicializador da table function input (uma consulta no formato INSERT INTO <table> SELECT ... FROM input('<structure>'), que transmite linhas do cliente). Logo após o servidor enviar o bloco Data do esquema de entrada (veja a fase de INSERT), ele emite TimezoneUpdate com o session_timezone atual do contexto da consulta, para que o cliente analise as linhas que está prestes a enviar com o mesmo fuso horário. O servidor não emite esse pacote para alterações arbitrárias de SET session_timezone no meio da consulta, nem para informar ao cliente como formatar blocos de resultado posteriores.
O pacote chega uma vez, imediatamente após o bloco de esquema de entrada e antes de o cliente começar a enviar blocos de linhas. Um decodificador que ignora
TimezoneUpdate AINDA DEVE consumir a String final para manter o wire alinhado.
Autenticação SSH por desafio-resposta (tipos de pacote 11, 12, 18)
SSH_AUTHENTICATION (v54466) e habilitada apenas por ativação explícita. Uma conexão entra no fluxo SSH quando ClientHello envia user = " SSH KEY AUTHENTICATION " + <real_user> (com os espaços iniciais e finais) e password = "". O servidor lê o prefixo, remove-o para recuperar o usuário real e passa para o modo desafio-resposta.
O fluxo é executado no lugar da autenticação por senha, e a troca de desafio-resposta acontece antes de
ServerHello — o servidor adia sua resposta Hello até que a autenticação seja concluída com sucesso:
-
O cliente envia
ClientHellocom o prefixo marcador SSH e uma senha vazia. -
O cliente envia
SSHChallengeRequest(pacote 11). O servidor ainda não enviouServerHello— ele primeiro processa a autenticação e fica aguardando esse pacote. -
O servidor responde com
SSHChallengetrazendo bytes aleatórios (pacote 18). -
O cliente monta a string a ser assinada e assina essa string, não o desafio bruto, depois envia
SSHChallengeResponse(pacote 12) com a assinatura. A mensagem assinada é a concatenação byte a byte, sem separadores, de quatro partes nesta ordem exata: -
O servidor verifica a assinatura usando a chave pública registrada do usuário, reconstruindo a mesma string
decimal(protocol_version) + default_database + user + challenge. Em caso de sucesso, ele enviaServerHello— a mesma resposta do fluxo por senha — e o handshake continua normalmente (Addendum etc.); em caso de falha, retorna umaExceptione encerra a conexão. Um cliente que assinar apenas os bytes brutos dechallengefalhará na autenticação.
Isso é o inverso do handshake de senha, em que
ServerHello vem imediatamente após ClientHello. Na autenticação SSH, ServerHello fica retido até que a assinatura seja verificada, de modo que o mecanismo de desafio-resposta do SSH é intercalado ao handshake antes que qualquer ServerHello apareça.Referência de tipos de pacote
Cliente → Servidor
Servidor → Cliente
Configuração
- Configurações da camada de transporte — opções de socket TCP e timeouts, que afetam o comportamento da própria conexão TCP.
- Configurações da camada de aplicação — ajustes por consulta incluídos na lista de configurações do pacote consulta, que afetam o que o servidor envia no wire ou como isso é estruturado.
- Configurações fora do escopo — configurações frequentemente confundidas com configurações de protocolo, mas que na verdade controlam a execução de SQL ou o armazenamento.
Configurações da camada de transporte
Opções de socket
Timeouts
Os timeouts se encadeiam assim:
Limites de conexão
Uma conexão que executa consultas regularmente pode permanecer ativa indefinidamente. Apenas conexões ociosas são encerradas após uma hora, e não há um ciclo de vida máximo padrão.
Configurações da camada de aplicação
Compressão
O sinalizador
compression no pacote consulta (campo 6) ativa e desativa a compressão; essas configurações definem qual codec é usado quando ele está ativado.
Streaming de logs
Configurar
send_logs_level com qualquer valor diferente de "none" faz com que o servidor emita pacotes de Log durante a execução da consulta.
Relatório de Progress
Este é um mínimo esperado, não um máximo rígido: o servidor pode enviar pacotes Progress com menos frequência quando a consulta não estiver gerando trabalho com rapidez suficiente.
Envelope do resultado
INSERT assíncrono
Rastreamento distribuído
Configurações fora do escopo
max_threads— paralelismo na execução da consulta.max_memory_usage— limite de memória por consulta.max_block_size,preferred_block_size_bytes— dimensionamento interno de blocos durante o processamento da consulta; os blocos wire são independentes dessas configurações.compile_expressions— compilação JIT; afeta apenas a CPU.async_insert_max_data_size— buffer da fila no servidor.- Todas as configurações
input_format_*eoutput_format_*, exceto a famíliainput_format_native_*/output_format_native_*— as não-nativeselecionam ou ajustam outros formatos (por exemplo, via HTTP) e não alteram os blocosDatado protocolo nativo.
*_native_* são a exceção: elas alteram os bytes dentro dos blocos Data do native TCP, portanto uma implementação de protocolo deve levá-las em conta. output_format_native_encode_types_in_binary_format muda o campo type da coluna de uma string textual para uma codificação binária de tipo, output_format_native_write_json_as_string emite colunas JSON como String, e output_format_native_use_flattened_dynamic_and_json_serialization seleciona o layout FLATTENED de Dynamic/JSON. Como elas afetam o body do bloco, e não o envelope do pacote, elas são especificadas na especificação Native Format — consulte layout wire da coluna e tipos versionados.
Glossário
- Consulta normal (
SELECT, etc.): enviado após o pacote consulta e quaisquer pacotes Data de tabelas externas para sinalizar “não há mais dados externos”. O servidor então inicia a execução. INSERT: o cliente não envia um marcador antes do esquema. O servidor envia primeiro o bloco de esquema, o cliente transmite seus blocos Data de linhas e só então envia o pacote Data vazio para encerrar o fluxo de linhas. Enviar um marcador vazio antes do bloco de esquema seria interpretado como um fim imediato das linhas, e os dados seriam perdidos.
min(client_version, server_version), calculada durante o handshake. Determina quais recursos ficam ativos durante o ciclo de vida da conexão.
Pacote — uma mensagem wire: um código de tipo de pacote VarUInt seguido por um body cujo formato depende do tipo. Veja envelope do pacote.
Código de tipo de pacote — o VarUInt inicial de um pacote que identifica seu formato. Os valores de 0 a 18 estão atribuídos no momento. Veja a referência de tipos de pacote.
Fluxo de resposta — a sequência de pacotes que o servidor emite durante uma consulta. Seu comprimento é indefinido e ele é encerrado por exatamente um EndOfStream (sucesso) ou Exception (falha). Veja a fase da consulta.
Bloco de esquema — o bloco de cabeçalho (um Block com colunas, mas 0 linhas) que o servidor envia durante a fase de INSERT para informar os formatos de coluna esperados antes de o cliente enviar os dados.
Lista de configurações — uma sequência de tuplas (key, flags, value) no body de consulta, terminada por uma chave vazia. Carrega a configuração por consulta na camada de aplicação. Veja SETTING.
Estágio — um campo VarUInt no pacote consulta (campo 5) que controla até onde o servidor executa a consulta. Clientes externos normalmente enviam 2 (Complete); consultas distribuídas e planos de consulta serializados usam os valores mais altos. Veja o campo 5 de consulta para o conjunto completo de valores wire.
Terminador — um pacote que encerra um fluxo. A resposta de consulta termina em EndOfStream (sucesso) ou Exception (falha). O fluxo de entrada do cliente termina no marcador Data vazio.