> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-trino-dialect.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> PREWHERE 절 문서

# PREWHERE 절

`PREWHERE`는 읽어야 하는 데이터 양을 줄여 필터링 효율을 높일 수 있습니다. 기본적으로 ClickHouse는 쿼리에서 `PREWHERE`를 명시적으로 지정하지 않아도 [`WHERE`](/ko/reference/statements/select/where)의 적합한 조건을 `PREWHERE`로 옮겨 이 최적화를 적용합니다. 이 단계에서 적용할 조건을 제어하려면 `PREWHERE`를 명시적으로 지정할 수 있습니다.

`PREWHERE`를 사용하면 ClickHouse는 먼저 조건 평가에 필요한 컬럼만 읽습니다. 그런 다음 일치하는 행이 하나 이상 포함된 블록에 대해서만 쿼리에 필요한 나머지 컬럼을 읽습니다. 조건에 사용되는 컬럼이 쿼리의 나머지 부분에서 사용하는 컬럼보다 적고 많은 블록이 필터링되는 경우, 읽어야 하는 데이터 양을 줄일 수 있습니다.

<div id="controlling-prewhere-manually">
  ## `PREWHERE` 수동 제어하기
</div>

조건이 적은 수의 컬럼만 참조하면서 많은 행을 필터링하는 경우 `PREWHERE`를 수동으로 지정하십시오. 이렇게 하면 나머지 컬럼에서 읽는 데이터 양을 줄일 수 있습니다.

쿼리에는 `PREWHERE`와 `WHERE`를 모두 포함할 수 있습니다. 이 경우 `PREWHERE`가 먼저 평가됩니다.

ClickHouse가 조건을 `WHERE`에서 `PREWHERE`로 자동 이동하지 않도록 하려면 [`optimize_move_to_prewhere`](/ko/reference/settings/session-settings/optimize-move-to-prewhere#optimize_move_to_prewhere)를 `0`으로 설정하십시오.

[`FINAL`](/ko/reference/statements/select/from#final-modifier) 수정자가 있는 쿼리에서는 [`optimize_move_to_prewhere`](/ko/reference/settings/session-settings/optimize-move-to-prewhere#optimize_move_to_prewhere)와 [`optimize_move_to_prewhere_if_final`](/ko/reference/settings/session-settings/optimize-move-to-prewhere#optimize_move_to_prewhere_if_final)가 모두 활성화된 경우에만 ClickHouse가 조건을 `WHERE`에서 `PREWHERE`로 이동합니다.

<Note>
  기본적으로 `PREWHERE`는 `FINAL`보다 먼저 평가됩니다. 따라서 `PREWHERE`가 테이블의 `ORDER BY` 키에 포함되지 않은 컬럼을 참조하면 `FROM ... FINAL` 쿼리에서 예기치 않은 결과가 발생할 수 있습니다.
</Note>

<div id="prewhere-with-join">
  ## `JOIN`에서의 `PREWHERE`
</div>

[`JOIN`](/ko/reference/statements/select/join)이 포함된 쿼리에서 `PREWHERE` 조건은 최대 하나의 테이블의 컬럼만 직접 참조할 수 있습니다. ClickHouse는 조인에 도달하기 전에 해당 테이블의 행에 이 조건을 적용합니다.

반면 `WHERE` 조건은 논리적으로 조인된 결과를 필터링합니다. 다만 결과가 달라지지 않는다면 최적화기가 조인 전에 조건을 적용할 수 있습니다. 따라서 동일한 조건을 `PREWHERE`와 `WHERE`에 사용하면, 특히 외부 조인에서는 서로 다른 결과가 나올 수 있습니다.

다음 예시에서는 이러한 차이를 보여 주기 위해 두 개의 테이블을 생성합니다:

```sql theme={null}
CREATE TABLE table_1
(
    `id` UInt32,
    `value` String
)
ENGINE = MergeTree
ORDER BY id;

CREATE TABLE table_2
(
    `id` UInt32,
    `value` String
)
ENGINE = MergeTree
ORDER BY id;

INSERT INTO table_1 VALUES (1, 'a'), (2, 'b'), (3, 'c');
INSERT INTO table_2 VALUES (1, 'x'), (2, 'y'), (3, 'z');
```

첫 번째 쿼리에서는 `PREWHERE`가 `LEFT JOIN` 전에 `table_2`를 필터링하므로, `id = 1`인 `table_1`의 행은 일치하는 행 없이 남습니다:

```sql theme={null}
SELECT
    table_1.id,
    table_1.value,
    table_2.value
FROM table_1
LEFT JOIN table_2 ON table_1.id = table_2.id
PREWHERE table_2.id >= 2
ORDER BY table_1.id;
```

```text theme={null}
   ┌─id─┬─value─┬─table_2.value─┐
1. │  1 │ a     │               │
2. │  2 │ b     │ y             │
3. │  3 │ c     │ z             │
   └────┴───────┴───────────────┘
```

`WHERE`에서 동일한 조건을 사용하면 JOIN 결과가 필터링되어 `id = 1`인 행이 제거됩니다:

```sql theme={null}
SELECT
    table_1.id,
    table_1.value,
    table_2.value
FROM table_1
LEFT JOIN table_2 ON table_1.id = table_2.id
WHERE table_2.id >= 2
ORDER BY table_1.id;
```

```text theme={null}
   ┌─id─┬─value─┬─table_2.value─┐
1. │  2 │ b     │ y             │
2. │  3 │ c     │ z             │
   └────┴───────┴───────────────┘
```

<div id="limitations">
  ## 제한 사항
</div>

`PREWHERE`는 [\*MergeTree](/ko/reference/engines/table-engines/mergetree-family/index) 계열 테이블에서만 지원됩니다.

<div id="example">
  ## 예시
</div>

```sql theme={null}
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.)

-- Enable tracing to see which predicates are moved to PREWHERE.
set send_logs_level='debug';

MergeTreeWhereOptimizer: condition "B = 0" moved to PREWHERE  
-- ClickHouse automatically moves B = 0 to PREWHERE, but this condition does not filter any rows because B is always 0.

-- Move the more selective C = 'x' predicate to PREWHERE.

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

-- The query with manually specified PREWHERE processes slightly less data: 158.89 MB instead of 168.89 MB.
```
