> ## 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` を使用すると、読み取るデータ量を削減し、フィルタリングを効率化できます。デフォルトでは、クエリで `PREWHERE` を明示的に指定していなくても、ClickHouse は対象となる条件を [`WHERE`](/ja/reference/statements/select/where) から `PREWHERE` に移動して、この最適化を適用します。この段階で適用する条件を制御するには、`PREWHERE` を明示的に指定します。

`PREWHERE` では、ClickHouse はまず条件の評価に必要なカラムだけを読み取ります。次に、一致する行を少なくとも 1 行含むブロックに対してのみ、クエリで必要な他のカラムを読み取ります。条件で使用するカラム数がクエリの他の部分より少なく、多くのブロックを除外できる場合、読み取るデータ量を削減できます。

<div id="controlling-prewhere-manually">
  ## `PREWHERE` を手動で制御する
</div>

条件が少数のカラムのみを参照し、多くの行を除外する場合は、`PREWHERE` を手動で指定します。これにより、残りのカラムから読み取るデータ量を削減できます。

クエリには `PREWHERE` と `WHERE` の両方を含めることができます。この場合、`PREWHERE` が先に評価されます。

ClickHouse が条件を `WHERE` から `PREWHERE` に自動的に移動しないようにするには、[`optimize_move_to_prewhere`](/ja/reference/settings/session-settings/optimize-move-to-prewhere#optimize_move_to_prewhere) を `0` に設定します。

[`FINAL`](/ja/reference/statements/select/from#final-modifier) 修飾子を使用するクエリでは、[`optimize_move_to_prewhere`](/ja/reference/settings/session-settings/optimize-move-to-prewhere#optimize_move_to_prewhere) と [`optimize_move_to_prewhere_if_final`](/ja/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`](/ja/reference/statements/select/join) を含むクエリでは、`PREWHERE` 条件が直接参照できるカラムは最大で1つのテーブルに限られます。ClickHouse は、結合前にそのテーブルの行に条件を適用します。

一方、`WHERE` 条件は論理上、結合結果をフィルタリングします。ただし、結果が変わらない場合、オプティマイザによって結合前に適用されることがあります。そのため、同じ条件を `PREWHERE` と `WHERE` で使用すると、特に外部結合では結果が異なる場合があります。

次の例では、この違いを示すために2つのテーブルを作成します。

```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` がフィルタリングされるため、`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` で同じ条件を使用すると、結合結果がフィルタリングされ、`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](/ja/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.
```
