Tipos de EXPLAIN
AST— Árvore de sintaxe abstrata.SYNTAX— Texto da consulta após otimizações no nível da AST.QUERY TREE— Árvore de consulta após otimizações no nível da árvore de consulta.PLAN— Plano de execução da consulta.PIPELINE— Pipeline de execução da consulta.ANALYZE— Executa a consulta e anota o plano de execução com métricas de runtime medidas.ESTIMATE— Número estimado de linhas, marcas e partes a serem lidas das tabelas durante o processamento da consulta.TABLE OVERRIDE— Resultado validado de um override de tabela em um esquema de função de tabela.
EXPLAIN AST
SELECT.
Configurações:
graph– Exibe a AST como um grafo descrito na linguagem de descrição de grafos DOT. Padrão: 0.
EXPLAIN SYNTAX
oneline– Imprime a consulta em uma única linha. Padrão:0.run_query_tree_passes– Executa os passes da árvore de consulta antes de exibi-la. Padrão:0.query_tree_passes– Serun_query_tree_passesestiver definido, especifica quantos passes executar. Sem especificarquery_tree_passes, ele executa todos os passes.
Query
Response
run_query_tree_passes:
Query
Response
EXPLAIN QUERY TREE
run_passes— Executa todos os passes da árvore de consulta antes de exibir a árvore de consulta. Padrão:1.dump_passes— Exibe informações sobre os passes usados antes de exibir a árvore de consulta. Padrão:0.passes— Especifica quantos passes devem ser executados. Se definido como-1, executa todos os passes. Padrão:-1.dump_tree— Exibe a árvore de consulta. Padrão:1.dump_ast— Exibe a AST da consulta gerada a partir da árvore de consulta. Padrão:0.
EXPLAIN PLAN
optimize— Controla se as otimizações do plano de consulta são aplicadas antes da exibição do plano. Padrão: 1.header— Exibe o cabeçalho de saída do passo. Padrão: 0.description— Exibe a descrição do passo. Padrão: 1.indexes— Mostra os índices usados, o número de partes filtradas e o número de grânulos filtrados para cada índice aplicado. Padrão: 0. Compatível com tabelas MergeTree. A partir do ClickHouse >= v25.9, esta instrução só exibe uma saída adequada quando usada comSETTINGS use_query_condition_cache = 0, use_skip_indexes_on_data_read = 0.projections— Mostra todas as projeções analisadas e seu efeito na filtragem no nível de partes com base nas condições da chave primária da projeção. Para cada projeção, esta seção inclui estatísticas como o número de partes, linhas, marcas e intervalos avaliados usando a chave primária da projeção. Também mostra quantas partes de dados foram ignoradas devido a essa filtragem, sem ler a própria projeção. Se uma projeção foi realmente usada para leitura ou apenas analisada para filtragem pode ser determinado pelo campodescription. Padrão: 0. Compatível com tabelas MergeTree.actions— Exibe informações detalhadas sobre as ações do passo. Padrão: 1.sorting— Exibe a descrição da ordenação para cada passo do plano que produz saída ordenada. Padrão: 0.keep_logical_steps— Mantém os passos lógicos do plano para junções em vez de convertê-los em implementações físicas de junção. Padrão: 0.json— Exibe os passos do plano de consulta como uma linha no formato JSON. Padrão: 0. Recomenda-se usar o formato TabSeparatedRaw (TSVRaw) para evitar escapes desnecessários.input_headers— Exibe os cabeçalhos de entrada do passo. Padrão: 0. Em geral, isso só é útil para desenvolvedores depurarem problemas relacionados à incompatibilidade entre cabeçalhos de entrada e saída.column_structure— Exibe também a estrutura das colunas nos cabeçalhos, além do nome e do tipo. Padrão: 0. Em geral, isso só é útil para desenvolvedores depurarem problemas relacionados à incompatibilidade entre cabeçalhos de entrada e saída.distributed— Mostra os planos de consulta executados em nós remotos para tabelas distribuídas ou réplicas paralelas. Não é compatível comjson. Padrão: 0.compact— Quando ativado, oculta do plano os passos de expressão e as informações detalhadas das ações (entradas, funções, aliases e posições de saída). Só tem efeito quandoactions = 1. Padrão: 1.pretty— Exibe a árvore do plano usando caracteres de desenho de linha (├──, └──, │) em vez de indentação para visualizar a hierarquia. Também formata as propriedades do passo de junção em linha. Padrão: 1.
Por padrão,
explain_query_plan_default = 'pretty', portanto actions, compact e pretty são inicializados com 1, e o plano é renderizado na forma compacta, com formatação pretty e com anotações de ações. Especificar explicitamente qualquer uma dessas opções na instrução EXPLAIN (por exemplo, EXPLAIN actions = 0, compact = 0, pretty = 0 SELECT ...) sempre substitui o padrão.Antes do ClickHouse 26.7, os valores padrão de actions, compact e pretty eram 0. Você ainda pode obter essa saída definindo explain_query_plan_default = 'legacy' (globalmente ou em SETTINGS por consulta) ou definindo compatibility para qualquer versão anterior à 26.7.As opções json e distributed não habilitam os padrões de pretty (actions, compact e pretty), mesmo quando explain_query_plan_default = 'pretty'. Para incluir detalhes das ações na saída delas, defina actions = 1 manualmente.Não há suporte à estimativa de custo do passo e da consulta.
json = 1, o plano da consulta é representado em formato JSON. Cada nó é um dicionário que sempre tem as chaves Node Type, Node Id e Plans. Node Type é uma string com o nome do passo, e Node Id é um identificador exclusivo do passo (o nome do passo com um sufixo numérico, por exemplo, Union_10). Plans é um array com descrições dos passos filhos. Outras chaves opcionais podem ser adicionadas dependendo do tipo de nó e das configurações.
Exemplo:
description = 1, a chave Description é adicionada ao passo:
header = 1, a chave Header é adicionada ao passo na forma de um array de colunas.
Exemplo:
indexes = 1, a chave Indexes é adicionada. Ela contém um array dos índices usados. Cada índice é descrito como JSON com a chave Type (uma string Partition Min-Max, Partition, Statistics, PrimaryKey ou Skip) e chaves opcionais:
Name— O nome do índice (atualmente usado apenas para índicesSkip).Keys— O array de colunas usado pelo índice.Condition— A condição usada.Description— A descrição do índice (atualmente usada apenas para índicesSkip).Parts— O número de partes após/antes da aplicação do índice.Granules— O número de grânulos após/antes da aplicação do índice.Ranges— O número de intervalos de grânulos após a aplicação do índice.
projections = 1, a chave Projections é adicionada. Ela contém um array de projeções analisadas. Cada projeção é descrita como JSON com as seguintes chaves:
Name— O nome da projeção.Condition— A condição da chave primária usada pela projeção.Description— A descrição de como a projeção é usada (por exemplo, filtragem em nível de partes).Selected Parts— Número de partes selecionadas pela projeção.Selected Marks— Número de marcas selecionadas.Selected Ranges— Número de intervalos selecionados.Selected Rows— Número de linhas selecionadas.Filtered Parts— Número de partes ignoradas devido à filtragem em nível de partes.
actions = 1, as chaves adicionadas dependem do tipo de passo.
Exemplo:
compact = 0 e actions = 1, os passos de Expression podem ser vistos juntamente com informações detalhadas sobre as expressões:
distributed = 1, a saída inclui não apenas o plano de consulta local, mas também os planos de consulta que serão executados nos nós remotos. Isso é útil para analisar e depurar consultas distribuídas.
distributed é exibido apenas na forma legacy (sem pretty), porque a saída pretty não integra os planos de shard remotos à árvore do plano. Por esse motivo, habilitar distributed desabilita automaticamente os padrões de pretty (actions, compact e pretty), independentemente de explain_query_plan_default. Você ainda pode definir actions=1 manualmente. A opção distributed também não é compatível com json.pretty = 1, a árvore do plano é exibida usando caracteres de desenho de linhas em vez de recuo, e informações adicionais são mostradas para os passos principais:
- As colunas de saída da consulta são exibidas no topo do plano.
- Expressões em filtros, chaves de agregação, descrições de ordenação e funções de janela são exibidas em uma notação semelhante a SQL legível por humanos (por exemplo,
a + 1 > 5em vez degreater(plus(a, 1), 5)). Os prefixos internos de identificadores de coluna (como__table1.) são removidos para maior clareza. - Passos de origem (como
ReadFromMergeTree) exibem suas colunas de saída. - Passos de filtro exibem a condição de filtro em notação SQL. Quando há filtros de join em tempo de execução, eles são mostrados separadamente.
- Passos de agregação exibem chaves e funções de agregação com seus argumentos (por exemplo,
sum(c),count()). - Conjuntos de
INde literais Tuple mostram seus valores (truncados para conjuntos grandes), conjuntos baseados em subconsulta são rotulados comosubquery1,subquery2etc., e conjuntos de tabelas com o motorSetmostram o nome da tabela. - Passos de join exibem a relação de join usando notação matemática, a contagem estimada de linhas do resultado, e quais colunas de saída vêm do lado esquerdo e do lado direito. Os símbolos a seguir são usados para representar diferentes tipos de join:
Por exemplo,
t1 ⟕ t2 significa uma junção à esquerda entre as tabelas t1 e t2.
O número entre colchetes após o nome da tabela (por exemplo, t1[100]) indica a contagem estimada de linhas
quando há estatísticas da tabela disponíveis.
A opção pretty funciona bem em conjunto com compact = 1, que oculta os passos Expression e as informações detalhadas de ações, tornando o plano mais fácil de ler.
Um exemplo detalhado com junções:
EXPLAIN PIPELINE
header— Imprime o cabeçalho de cada porta de saída. Padrão: 0.graph— Imprime um grafo descrito na linguagem de descrição de grafos DOT. Padrão: 0.compact— Imprime o grafo no modo compacto se a configuraçãographestiver habilitada. Padrão: 1.compact_repeated_processor_chains— Compacta cadeias repetidas adjacentes de processadores na saída de texto, mostrando uma cópia da cadeia com uma contagem de repetições. Isso pode facilitar a leitura de pipelines paralelos quando a mesma cadeia aparece muitas vezes, por exemplo, em junções. Isso não afeta a saída do grafo. Padrão: 0.
compact=0 e graph=1, os nomes dos processadores conterão um sufixo adicional com um identificador exclusivo do processador.
Exemplo:
EXPLAIN ANALYZE
EXPLAIN ANALYZE de fato executa a consulta, descarta as linhas de resultado e imprime a mesma árvore de plano que EXPLAIN PLAN, com cada passo anotado com o que realmente aconteceu em tempo de execução.
Configurações:
EXPLAIN ANALYZE aceita as mesmas opções de exibição que EXPLAIN PLAN (documentadas na seção EXPLAIN PLAN).
header— consulte a seção EXPLAIN PLAN.description— consulte a seção EXPLAIN PLAN.projections— consulte a seção EXPLAIN PLAN.sorting— consulte a seção EXPLAIN PLAN.input_headers— consulte a seção EXPLAIN PLAN.column_structure— consulte a seção EXPLAIN PLAN.actions— consulte a seção EXPLAIN PLAN. Padrão: 1.indexes— consulte a seção EXPLAIN PLAN. Padrão: 1.compact— consulte a seção EXPLAIN PLAN. Padrão: 1.pretty— consulte a seção EXPLAIN PLAN. Padrão: 1.processors— ParaEXPLAIN ANALYZE, imprime uma linha adicional por estágio com a distribuição do tempo decorrido por processador:min,median,maxesum. Útil para identificar desequilíbrio de carga entre processadores paralelos. Padrão: 0.
Como
EXPLAIN ANALYZE realmente executa a consulta encapsulada, ele se comporta como essa
consulta — e, diferentemente das formas EXPLAIN que não executam — de várias maneiras:- Cotas e limites. Ele é contabilizado nas mesmas quotas
e está sujeito aos mesmos limits
(por exemplo,
query_selects,read_rows) que a execução direta da consulta. Fontes isentas de cotas durante o planejamento (comosystem.one) não são contabilizadas. - Transações com falha. Dentro de uma transação
que já falhou (
ROLLED_BACK), ele é rejeitado comINVALID_TRANSACTION, assim como uma instruçãoSELECTsimples — emitaROLLBACKprimeiro. - Leituras de streaming. Em uma leitura de streaming (
FROM ... STREAM), ele é rejeitado comNOT_IMPLEMENTED, porque esse tipo de leitura nunca termina. - Consultas distribuídas. Não há suporte para ele em consultas executadas em modo Distributed.
Time— tempo total dividido entre as fases de planejamento (isto é, criação do plano + otimização do plano + construção do pipeline) e execução (execução do pipeline).Read— linhas e bytes não comprimidos lidos das tabelas, com a taxa de transferência — os mesmos números que o rodapé padrão da consulta informa como “Processed”.Peak memory— pico de memória usado pela consulta.
I/O). O tempo e o paralelismo são informados por estágio do passo nas linhas indentadas abaixo.
rows <in> → <out>— linhas que entraram e saíram do passo; (<selectivity>%) mostra o quanto o passo filtrou (out/in) ou expandiu os dados; fica oculto quando as linhas de entrada são iguais às linhas de saída e quando as linhas de entrada são iguais a0.<bytes_in> → <bytes_out>— bytes não comprimidos em memória que passam pelo passo (omitido quando ambos são zero).time <t> (<share>%)— tempo de relógio em que o estágio esteve ativo e sua participação no tempo de execução da consulta (isto é, sem o tempo de compilação). Observe que as participações podem somar mais de 100%, porque estágios e passos são executados de forma concorrente.parallelism <avg>/<max>— número médio de threads de CPU trabalhando ao mesmo tempo neste estágio, do máximo que ele poderia usar. Um valor próximo do máximo significa que o estágio foi bem paralelizado; próximo de 1 significa que ele foi executado principalmente de forma serial.Stage (<stage>)— o nome do estágio. Um passo com um único estágio imprime a linha de tempo diretamente, sem um rótuloStage (...). Passos com vários estágios imprimem uma linha identificada para cada estágio; por exemplo,AggregatingmostraStage (partial aggregation)eStage (final aggregation), e um hash join mostraStage (build)eStage (probe).
O ClickHouse paraleliza não apenas a execução de tarefas dentro de um passo do plano, mas também a execução dos próprios passos do plano. A métrica
parallelism reflete apenas o trabalho deste passo. Outros passos podem ser executados de forma concorrente, portanto esse número não mostra como o paralelismo do passo se compara ao da consulta como um todo.O número máximo em
parallelism é calculado como o valor mínimo entre:- o número total de tarefas dentro do passo do plano;
- o número máximo de threads de processamento de consultas definido em
max_threads.
processors = 1, uma linha extra é impressa abaixo de cada estágio, mostrando a distribuição do tempo decorrido entre os processadores do estágio:
<n> é o número de processadores no estágio. Uma grande diferença entre median e max indica um desequilíbrio de carga entre processadores paralelos.
EXPLAIN ESTIMATE
Query
Query
Response
EXPLAIN WHATIF
SELECT, sem materializar o índice em disco. Defina um ou mais candidatos com CREATE HYPOTHETICAL INDEX e, em seguida, execute EXPLAIN WHATIF SELECT ... para ver, para cada candidato: aplicabilidade, marcas lidas estimadas, bytes estimados e taxa de descarte.
Sintaxe
empirical—1(padrão) executa o índice em memória sobre os grânulos filtrados pela referência para medir a taxa de descarte (um limite superior).0ignora esse caminho. De qualquer forma, seempiricalnão produzir um resultado (por estar desabilitado ou porque o índice não pode ser avaliado em memória), o estimador recorre às estatísticas da coluna e, por fim, a um resumo apenas de aplicabilidade se nenhuma das duas opções estiver disponível.
source— como a estimativa foi gerada.empirical: construiu o índice em memória sobre os grânulos remanescentes após o pruning de referência e contou os grânulos que o índice pularia. Este é um limite superior — veja as limitações emCREATE HYPOTHETICAL INDEX.statistical: derivado de estatísticas de coluna. Usado quando a estimativa empírica está desabilitada (empirical = 0) ou não conseguiu produzir um resultado, e há estatísticas de coluna definidas nas colunas relevantes.applicability_only: o índice é aplicável ao predicado, mas nem a estimativa empírica nem a estatística produziram um resultado (por exemplo,empirical = 0e nenhuma estatística de coluna definida). Informaskip_ratio: 0.0%como um limite conservador.
sampled_parts/sampled_marks—<baseline-pruned> / <total in the table>. Mostra que fração da tabela restou após o pruning por PK, partição e índices existentes, ou seja, a entrada para o índice hipotético.est_bytes— uma estimativa dos bytes lidos, derivada do tamanho médio de linha da tabela; por isso, é aproximada e varia conforme o armazenamento e a compressão. A linha de referência aparece apenas quando a consulta lê linhas; a linha de cada candidato, apenas quando a estimativa de bytes da linha de referência é conhecida.
WHATIF e SELECT — não há palavra-chave SETTINGS (isso corresponde à forma como outras variantes de EXPLAIN aceitam suas opções).
Se nenhum índice hipotético estiver definido para a tabela, EXPLAIN WHATIF informa status: not_applicable com uma dica para criar um.
Linha combinada (múltiplos candidatos)
Quando dois ou mais candidatos são avaliados empiricamente, EXPLAIN WHATIF acrescenta um bloco extra chamado (combined: idx_a, idx_b, ...) após as linhas de cada candidato. Ele informa o benefício conjunto de ter todos esses índices ao mesmo tempo: uma leitura real mantém um grânulo apenas se ele sobreviver a todos os skip indexes, portanto a estimativa combinada é a interseção dos grânulos sobreviventes dos candidatos. Seu skip_ratio é, portanto, pelo menos tão alto quanto o do melhor candidato individual — índices complementares fazem mais pruning em conjunto, enquanto índices redundantes o mantêm inalterado.
Só contribuem os candidatos com source: empirical, porque a linha combinada é formada pela interseção dos conjuntos de sobrevivência por grânulo de cada um. Os candidatos estimados como statistical ou applicability_only não têm dados por grânulo e são excluídos; consequentemente, o bloco combinado aparece somente quando pelo menos dois candidatos produziram uma estimativa empírica, e é omitido caso contrário (por exemplo, com empirical = 0). Seus campos de estimativa são os mesmos de um bloco empírico por candidato, exceto que elapsed_us é 0 — a estimativa combinada é derivada das varreduras por candidato, não de uma nova varredura. O nome sintético (combined: ...) é apenas um rótulo do relatório e não pode ser usado com force_data_skipping_indices.
Exemplo empírico
minmax hipotético reduziria de 100 marcas para 1 — skip_ratio: 99.0%. (est_bytes é uma estimativa com base no tamanho médio da linha, portanto o valor exato varia.)
Exemplo estatístico
As estatísticas de coluna vêm desativadas por padrão. Para usar o caminho statistical, primeiro defina-as nas colunas relevantes e aguarde a conclusão da mutação de materialização:
b < 10 (cerca de 10 linhas em 10000) e é informado como um limite superior de skip_ratio. Não há sampled_parts / sampled_marks — nenhum dado foi lido.
Se nenhum dos dois caminhos estiver disponível (por exemplo, empirical = 0 e nenhuma estatística de coluna definida), o estimador informa source: applicability_only e um skip_ratio: 0.0% conservador.
EXPLAIN TABLE OVERRIDE
Query
Query
Response
A validação não está completa, portanto uma consulta bem-sucedida não garante que o override não cause problemas.