메인 콘텐츠로 건너뛰기
PREWHERE는 필터링을 더 효율적으로 적용하기 위한 최적화입니다. PREWHERE 절을 명시적으로 지정하지 않아도 기본적으로 활성화됩니다. 이 최적화는 WHERE 조건의 일부를 PREWHERE 단계로 자동으로 이동해 동작합니다. PREWHERE 절의 역할은 기본 방식보다 더 적절하게 제어할 수 있다고 판단할 때 이 최적화를 직접 제어하는 데 있습니다. PREWHERE 최적화를 사용하면 먼저 PREWHERE 표현식을 실행하는 데 필요한 컬럼만 읽습니다. 그런 다음 나머지 쿼리를 실행하는 데 필요한 다른 컬럼을 읽는데, 일부 행에서라도 PREWHERE 표현식이 true인 블록만 읽습니다. 모든 행에서 PREWHERE 표현식이 false인 블록이 많고 PREWHERE에 필요한 컬럼 수가 쿼리의 다른 부분보다 적다면, 쿼리 실행 시 디스크에서 읽는 데이터 양을 크게 줄일 수 있는 경우가 많습니다.

PREWHERE 수동 제어

이 절은 WHERE 절과 같은 의미를 가집니다. 차이점은 테이블에서 어떤 데이터를 읽는지에 있습니다. 쿼리에서 일부 컬럼에만 사용되지만 데이터 필터링 효과가 큰 조건에 대해 PREWHERE를 수동으로 제어하면 읽어야 하는 데이터 양을 줄일 수 있습니다. 하나의 쿼리에서 PREWHEREWHERE를 동시에 지정할 수 있습니다. 이 경우 PREWHEREWHERE보다 먼저 적용됩니다. optimize_move_to_prewhere 설정이 0으로 되어 있으면 표현식의 일부를 WHERE에서 PREWHERE로 자동 이동하는 휴리스틱이 비활성화됩니다. 쿼리에 FINAL 수정자가 있으면 PREWHERE 최적화가 항상 올바르게 동작하는 것은 아닙니다. 이 최적화는 optimize_move_to_prewhereoptimize_move_to_prewhere_if_final 설정이 모두 활성화되어 있을 때만 적용됩니다.
PREWHERE 절은 FINAL보다 먼저 실행되므로, 테이블의 ORDER BY 절에 없는 필드에 PREWHERE를 사용하면 FROM ... FINAL 쿼리 결과가 왜곡될 수 있습니다.

제한 사항

PREWHERE*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.)

-- PREWHERE로 이동되는 프레디케이트를 확인하기 위해 트레이싱을 활성화합니다
set send_logs_level='debug';

MergeTreeWhereOptimizer: condition "B = 0" moved to PREWHERE  
-- ClickHouse가 `B = 0`을 자동으로 PREWHERE로 이동하지만, B는 항상 0이므로 실질적인 의미가 없습니다.

-- 다른 프레디케이트 `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.)

-- `PREWHERE`를 수동으로 지정한 이 쿼리는 처리하는 데이터 양이 약간 더 적습니다: 158.89 MB VS 168.89 MB
마지막 수정일 2026년 6월 10일