> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> Документация по предложению PREWHERE

# Предложение PREWHERE

`PREWHERE` позволяет повысить эффективность фильтрации, сократив объём считываемых данных. По умолчанию ClickHouse применяет эту оптимизацию даже если запрос явно не содержит `PREWHERE`: подходящие условия из [`WHERE`](/docs/ru/reference/statements/select/where) перемещаются в `PREWHERE`. Вы можете явно указать `PREWHERE`, чтобы контролировать, какие условия применяются на этом этапе.

При использовании `PREWHERE` ClickHouse сначала считывает только столбцы, необходимые для вычисления условия. Затем остальные столбцы, требуемые запросом, считываются только для блоков, содержащих хотя бы одну подходящую строку. Это может сократить объём считываемых данных, если условие использует меньше столбцов, чем остальная часть запроса, и отфильтровывает множество блоков.

<div id="controlling-prewhere-manually">
  ## Ручное управление `PREWHERE`
</div>

Указывайте `PREWHERE` вручную, если условие ссылается на небольшое число столбцов и отфильтровывает много строк. Это позволяет сократить объём данных, считываемых из остальных столбцов.

Запрос может содержать и `PREWHERE`, и `WHERE`. В этом случае `PREWHERE` вычисляется первым.

Установите для [`optimize_move_to_prewhere`](/docs/ru/reference/settings/session-settings/optimize-move-to-prewhere#optimize_move_to_prewhere) значение `0`, чтобы запретить ClickHouse автоматически перемещать условия из `WHERE` в `PREWHERE`.

В запросах с модификатором [`FINAL`](/docs/ru/reference/statements/select/from#final-modifier) ClickHouse перемещает условия из `WHERE` в `PREWHERE`, только если включены и [`optimize_move_to_prewhere`](/docs/ru/reference/settings/session-settings/optimize-move-to-prewhere#optimize_move_to_prewhere), и [`optimize_move_to_prewhere_if_final`](/docs/ru/reference/settings/session-settings/optimize-move-to-prewhere#optimize_move_to_prewhere_if_final).

<Note>
  По умолчанию `PREWHERE` вычисляется до `FINAL`, поэтому запросы `FROM ... FINAL` могут давать неожиданные результаты, если `PREWHERE` ссылается на столбцы, не входящие в ключ `ORDER BY` таблицы.
</Note>

<div id="prewhere-with-join">
  ## `PREWHERE` с `JOIN`
</div>

Условие `PREWHERE` в запросе с [`JOIN`](/docs/ru/reference/statements/select/join) может напрямую ссылаться на столбцы только одной таблицы. ClickHouse применяет условие к строкам этой таблицы до их участия в JOIN.

Напротив, условие `WHERE` логически фильтрует результат JOIN, хотя оптимизатор может применить его до JOIN, если это не изменит результат. Поэтому использование одного и того же условия в `PREWHERE` и `WHERE` может давать разные результаты, особенно при внешних JOIN.

В следующем примере создаются две таблицы, чтобы продемонстрировать эту разницу:

```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` фильтрует `table_2` перед выполнением `LEFT JOIN`, поэтому для строки из `table_1` с `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
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](/docs/ru/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.
```
