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

> DISTINCT 句のリファレンス

# DISTINCT

`SELECT DISTINCT` を指定すると、クエリ結果には一意の行だけが残ります。つまり、結果内で完全に一致する行の組ごとに、1 行だけが残ります。

一意の値を持つ必要があるカラムの一覧は `SELECT DISTINCT ON (column1, column2,...)` のように指定できます。カラムを指定しない場合は、すべてのカラムが対象になります。

次のテーブルを考えます:

```text theme={null}
┌─a─┬─b─┬─c─┐
│ 1 │ 1 │ 1 │
│ 1 │ 1 │ 1 │
│ 2 │ 2 │ 2 │
│ 2 │ 2 │ 2 │
│ 1 │ 1 │ 2 │
│ 1 │ 2 │ 2 │
└───┴───┴───┘
```

カラムを指定せずに `DISTINCT` を使用する場合:

```sql theme={null}
SELECT DISTINCT * FROM t1;
```

```text theme={null}
┌─a─┬─b─┬─c─┐
│ 1 │ 1 │ 1 │
│ 2 │ 2 │ 2 │
│ 1 │ 1 │ 2 │
│ 1 │ 2 │ 2 │
└───┴───┴───┘
```

指定したカラムで `DISTINCT` を使用する:

```sql theme={null}
SELECT DISTINCT ON (a,b) * FROM t1;
```

```text theme={null}
┌─a─┬─b─┬─c─┐
│ 1 │ 1 │ 1 │
│ 2 │ 2 │ 2 │
│ 1 │ 2 │ 2 │
└───┴───┴───┘
```

## DISTINCT と ORDER BY

ClickHouse では、1 つのクエリ内で `DISTINCT` 句と `ORDER BY` 句に異なるカラムを指定できます。`DISTINCT` 句は `ORDER BY` 句より先に実行されます。

次のテーブルを考えます。

```text theme={null}
┌─a─┬─b─┐
│ 2 │ 1 │
│ 1 │ 2 │
│ 3 │ 3 │
│ 2 │ 4 │
└───┴───┘
```

データの選択:

```sql theme={null}
SELECT DISTINCT a FROM t1 ORDER BY b ASC;
```

```text theme={null}
┌─a─┐
│ 2 │
│ 1 │
│ 3 │
└───┘
```

ソート方向を変えてデータを選択する場合:

```sql theme={null}
SELECT DISTINCT a FROM t1 ORDER BY b DESC;
```

```text theme={null}
┌─a─┐
│ 3 │
│ 1 │
│ 2 │
└───┘
```

行 `2, 4` はソート前に除外されました。

クエリを記述する際は、この実装上の特性を考慮してください。

## NULL の処理

`DISTINCT` は、[NULL](/ja/reference/syntax#null) を `NULL` が特定の値であり、`NULL==NULL` であるかのように扱います。つまり、`DISTINCT` の結果では、`NULL` を含む同じ組み合わせは 1 回しか現れません。これは、ほかの多くの文脈での `NULL` の扱いとは異なります。

## 代替手段

集約関数を使用しなくても、`SELECT` 句で指定したものと同じ値の組み合わせに対して [GROUP BY](/ja/reference/statements/select/group-by) を適用すれば、同じ結果を得ることができます。ただし、`GROUP BY` を使う方法とはいくつか異なる点があります。

* `DISTINCT` は `GROUP BY` と組み合わせて使用できます。
* 外部実行が開始される前であれば、[ORDER BY](/ja/reference/statements/select/order-by) を伴わないクエリは、[LIMIT](/ja/reference/statements/select/limit) を満たすのに十分な数の異なる行を読み込んだ時点で停止できます。
* 外部実行が開始される前で、かつ `ORDER BY` が省略されている場合、`ALL` を伴わない [`LIMIT ... AFTER ... UNTIL`](/ja/reference/statements/select/limit#limit-after-until) の範囲についても、その範囲が終了した時点でクエリを停止できます。
* データブロックは、外部実行が開始されるまでは、処理されるたびに出力されます。

## 外部メモリでのDISTINCT

`DISTINCT` は、メモリに保持しきれないほど大きな一意な値の集合を処理する際に、一時データをディスクへ書き出すことができます。その分ディスクI/Oが増えるため、クエリが遅くなる場合があります。

スピルを開始するタイミングは、次の2つの設定で制御します。

* `max_bytes_before_external_distinct` は、クエリのメモリ使用量合計に対するしきい値をバイト単位で設定します。デフォルトは `0` (無効) です。
* `max_bytes_ratio_before_external_distinct` は、サーバーまたはユーザーの制限下で利用可能なメモリに対する割合を設定します。この値は実行開始時点で測定されます。デフォルトは `0.5` で、いずれの制限も適用されない場合は効果がありません。

両方のしきい値が適用される場合は、小さい方が使用されます。スピルを無効にするには、両方の設定を `0` にしてください。

`max_memory_usage` は割合には影響しません。クエリのメモリ制限を基準にスピルを設定するには、その制限より小さい絶対しきい値を指定してください。たとえば次のクエリでは、256 MiBのクエリメモリ制限に対して16 MiBのスピルしきい値を使用しています。

```sql theme={null}
SELECT DISTINCT number % 1000000 AS id
FROM numbers(2000000)
SETTINGS
    max_bytes_before_external_distinct = 16777216,
    max_bytes_ratio_before_external_distinct = 0,
    max_memory_usage = 268435456;
```

これらのしきい値はメモリ使用量の上限を定めるものではありません。他のクエリ処理やスピル自体のための余裕を残しておいてください。また、メモリ逼迫時にはより早い段階でスピルが開始される場合があります。

スピルが発生する前に行が返されることがあり、この段階で `LIMIT` が満たされればクエリは早期に完了できます。
いったんスピルが始まると、残りの結果を返す前に入力の残り全体を読み取る必要があります。
クエリに `ORDER BY` が含まれる場合、それらの結果は要求された順序で返されます。

`DISTINCT` がそのキーのプレフィックスでソートされた入力を使用する場合、スピルは発生しません。ただし、同じプレフィックスを持つ行のグループが大きい場合は、依然としてかなりのメモリを消費する可能性があります。

`optimize_distinct_in_order` の場合と同様に、スピルによって、バイナリ表現は異なるが比較上は等しいと判定される浮動小数点値 (`0.0` と `-0.0` や、ペイロードの異なる `NaN` 値など) が重複排除されることがあります。
