Clickhouse: Cláusula PREWHERE

A Cláusula PREWHERE

Prewhere é uma otimização para aplicar filtragem de forma mais eficiente. Ela é habilitada por padrão mesmo se a cláusula PREWHERE não for especificada explicitamente, e funciona movendo automaticamente parte da condição WHERE para o estágio prewhere. A função da cláusula PREWHERE é apenas controlar essa otimização se você acha que sabe como fazê-la melhor do que acontece por padrão.

Com a otimização PREWHERE, a princípio, apenas as colunas necessárias para executar a expressão PREWHERE são lidas e  então as demais colunas necessárias são lidas para executar o restante da consulta, mas apenas aqueles blocos onde a expressão PREWHERE é true pelo menos para algumas linhas. Se houver muitos blocos onde a expressão PREWHERE é false para todas as linhas e o PREWHERE precisa de menos colunas do que outras partes da consulta, isso geralmente permite ler muito menos dados do disco para execução da consulta.

Controlando o PREWHERE

A cláusula tem o mesmo significado que a cláusula WHERE, mas a diferença está em quais dados são lidos da tabela. Ao controlar manualmente PREWHERE as condições de filtragem que são usadas por uma minoria das colunas na consulta, mas que fornecem filtragem de dados forte, será reduzido o volume de dados a serem lidos.

Uma consulta pode especificar simultaneamente PREWHERE e WHERE, e neste caso, PREWHERE precede WHERE.

Se a configuração optimize_move_to_prewhere for definida como 0, a heurística para mover automaticamente partes de expressões de WHERE para PREWHERE será desabilitada.

Se a consulta tiver modificador FINAL, a otimização PREWHERE nem sempre estará correta. Ela será habilitada somente se ambas as configurações optimize_move_to_prewhere e optimize_move_to_prewhere_if_final estiverem ativadas.

Observação

A seção PREWHERE é executada antes de FINAL, então os resultados das consultas FROM ... FINAL podem ser distorcidos quando usadascom campos PREWHERE que não estão na seção ORDER BY de uma tabela.

 

Limitações

PREWHERE é suportado apenas por tabelas da família *MergeTree .

CREATE TABLE mydata
(
    `A` Int64,
    `B` Int8,
    `C` String
)
ENGINE = MergeTree
ORDER BY A AS
SELECT
    number,
    0,
    if(number between 1000 and 2000, 'x', toString(number))
FROM numbers(10000000);

SELECT count()
FROM mydata
WHERE (B = 0) AND (C = 'x');

1 row in set. Elapsed: 0.074 sec. Processed 10.00 million rows, 168.89 MB (134.98 million rows/s., 2.28 GB/s.)

-- let's enable tracing to see which predicate are moved to PREWHERE
set send_logs_level='debug';

MergeTreeWhereOptimizer: condition "B = 0" moved to PREWHERE  
-- Clickhouse moves automatically `B = 0` to PREWHERE, but it has no sense because B is always 0.

-- Let's move other predicate `C = 'x'` 

SELECT count()
FROM mydata
PREWHERE C = 'x'
WHERE B = 0;

1 row in set. Elapsed: 0.069 sec. Processed 10.00 million rows, 158.89 MB (144.90 million rows/s., 2.30 GB/s.)

-- This query with manual `PREWHERE` processes slightly less data: 158.89 MB VS 168.89 MB


PREWHERE Clause. Clickhouse.com. Disponível em:
https://clickhouse.com/docs/en/sql-reference/statements/select/prewhere. Acesso em: 05 Jan 2024.

 

Data de Publicação: 27-08-2024

Categoria: Clickhouse