JOIN 句
JOIN 句は、各テーブルに共通する値を用いて 1 つ以上のテーブルの列を結合し、新しいテーブルを生成します。これは SQL をサポートするデータベースで一般的な操作であり、関係代数における join に相当します。単一のテーブル内での結合という特殊なケースは、しばしば「自己結合 (self-join)」と呼ばれます。
構文
ON 句の式および USING 句の列は「結合キー」と呼ばれます。特に断りがない限り、JOIN は一致する「結合キー」を持つ行から デカルト積 を生成し、その結果、元のテーブルよりもはるかに多くの行を含むことがあります。
サポートされている JOIN の種類
すべての標準的な SQL JOIN タイプがサポートされています:
| Type | Description |
|---|---|
INNER JOIN | 一致する行のみが返されます。 |
LEFT OUTER JOIN | 一致する行に加えて、左側のテーブルの一致しない行も返されます。 |
RIGHT OUTER JOIN | 一致する行に加えて、右側のテーブルの一致しない行も返されます。 |
FULL OUTER JOIN | 一致する行に加えて、両方のテーブルの一致しない行も返されます。 |
CROSS JOIN | テーブル全体のデカルト積を生成します。「join keys」は指定しません。 |
- 種類を指定しない
JOINはINNERを意味します。 - キーワード
OUTERは省略しても問題ありません。 CROSS JOINの代替構文として、複数のテーブルをカンマ区切りでFROM句 に指定する方法があります。
ClickHouse では、追加で次の JOIN タイプも利用できます:
| Type | Description |
|---|---|
LEFT SEMI JOIN, RIGHT SEMI JOIN | デカルト積を生成せずに、「join keys」に対する許可リストとして機能します。 |
LEFT ANTI JOIN, RIGHT ANTI JOIN | デカルト積を生成せずに、「join keys」に対する拒否リストとして機能します。 |
LEFT ANY JOIN, RIGHT ANY JOIN, INNER ANY JOIN | 標準的な JOIN タイプにおいて、LEFT と RIGHT の反対側に対しては部分的に、INNER と FULL に対しては完全に、デカルト積を無効化します。 |
ASOF JOIN, LEFT ASOF JOIN | 完全一致ではない条件でシーケンス同士を結合します。ASOF JOIN の使用方法は後述します。 |
PASTE JOIN | 2 つのテーブルを水平方向に連結します。 |
join_algorithm が partial_merge に設定されている場合、RIGHT JOIN および FULL JOIN は ALL ストリクト性の場合にのみサポートされます(SEMI、ANTI、ANY、ASOF はサポートされません)。
設定
デフォルトの結合種別は、join_default_strictness 設定で上書きできます。
ANY JOIN 演算に対する ClickHouse サーバーの動作は、any_join_distinct_right_table_keys 設定に依存します。
関連項目
join_algorithmjoin_any_take_last_rowjoin_use_nullspartial_merge_join_rows_in_right_blocksjoin_on_disk_max_files_to_mergeany_join_distinct_right_table_keys
ClickHouse が CROSS JOIN を INNER JOIN に書き換えられなかった場合の動作を指定するには、cross_to_inner_join_rewrite 設定を使用します。デフォルト値は 1 であり、この場合は結合を継続しますが、処理は遅くなります。エラーをスローしたい場合は cross_to_inner_join_rewrite を 0 に設定し、カンマ結合/クロス結合を実行せず、すべてのカンマ/クロス結合の書き換えを強制したい場合は 2 に設定します。値が 2 のときに書き換えが失敗すると、"Please, try to simplify WHERE section" というエラーメッセージが返されます。
ON 句の条件
ON 句には、AND や OR 演算子を使って組み合わせた複数の条件を含めることができます。結合キーを指定する条件は、次を満たす必要があります。
- 結合の左側および右側、両方のテーブルを参照すること
- 等値演算子を使用すること
その他の条件では他の論理演算子を使用できますが、クエリの左側または右側のいずれか一方のテーブルを参照していなければなりません。
複合条件全体が満たされた場合に行が結合されます。条件が満たされない場合でも、JOIN の種類によっては行が結果に含まれることがあります。同じ条件を WHERE 句に記述していて、それらが満たされない場合には、行は常に結果から除外される点に注意してください。
ON 句内の OR 演算子はハッシュ結合アルゴリズムで動作します。すなわち、JOIN の結合キーを含む各 OR 引数ごとに別々のハッシュテーブルが作成されるため、ON 句内の OR 式の数が増加すると、それに比例してメモリ消費量とクエリの実行時間が線形に増加します。
条件が異なるテーブルの列を参照している場合、現時点では等値演算子(=)のみがサポートされています。
例
table_1 と table_2 を考えます。
結合キー 1 つと table_2 に対する追加条件を指定したクエリ:
結果には、名前が C の行と、空の text 列が含まれていることに注意してください。これは、結合に OUTER 型が使用されているために含まれています。
INNER 結合と複数条件を使用したクエリ:
結果:
INNER 型の結合と OR 条件を用いたクエリ:
結果:
INNER 結合と OR および AND 条件を含むクエリ:
デフォルトでは、同じテーブルの列を使用している限り、非等価条件もサポートされます。
たとえば、t1.a = t2.key AND t1.b > 0 AND t2.b > t2.c のような条件は有効です。これは、t1.b > 0 が t1 の列のみを使用し、t2.b > t2.c が t2 の列のみを使用しているためです。
ただし、t1.a = t2.key AND t1.b > t2.key のような条件に対する実験的サポートを有効化して試すこともできます。詳細については、以下のセクションを参照してください。
結果:
異なるテーブルの列に対する不等号条件を用いた JOIN
ClickHouse は現在、等価条件に加えて、不等号条件を指定した ALL/ANY/SEMI/ANTI INNER/LEFT/RIGHT/FULL JOIN をサポートしています。不等号条件は、hash および grace_hash の JOIN アルゴリズムでのみ利用できます。不等号条件は join_use_nulls ではサポートされません。
例
テーブル t1:
テーブル t2
JOINキーにおけるNULL値
NULL は、自分自身を含めてどの値とも等しくありません。これは、あるテーブルの JOIN キーに NULL 値がある場合、他のテーブルの NULL 値とは一致しないことを意味します。
例
テーブル A:
テーブル B:
テーブル A の Charlie の行と、テーブル B のスコア 88 の行は、JOIN キーに NULL 値が含まれているため、結果に含まれていないことに注意してください。
NULL 値もマッチさせたい場合は、JOIN キーを比較するために isNotDistinctFrom 関数を使用してください。
ASOF JOIN の使用方法
ASOF JOIN は、完全一致するレコードが存在しないデータ同士を結合する必要がある場合に有用です。
この JOIN アルゴリズムでは、テーブル内に専用の列が必要です。この列は次の条件を満たす必要があります。
- 値が順序付けられたシーケンスになっていなければなりません。
- 次のいずれかの型である必要があります: Int, UInt, Float, Date, DateTime, Decimal。
hashJOIN アルゴリズムの場合、この列をJOIN句の唯一の列として指定することはできません。
構文 ASOF JOIN ... ON:
任意の数の等価条件と、最も近い一致条件を1つだけ使用できます。たとえば、SELECT count() FROM table_1 ASOF LEFT JOIN table_2 ON table_1.a == table_2.b AND table_2.t <= table_1.t のようになります。
最も近い一致条件でサポートされる演算子: >, >=, <, <=。
構文 ASOF JOIN ... USING:
ASOF JOIN は、等値結合に equi_columnX を使用し、table_1.asof_column >= table_2.asof_column という条件で「最も近い値」に基づく結合に asof_column を使用します。asof_column 列は常に USING 句の最後に記述されます。
例えば、次のテーブルを考えてみます。
ASOF JOIN は、table_1 のユーザーイベントのタイムスタンプを基準に、対応する最も近い一致条件に従って、そのタイムスタンプに最も近いタイムスタンプを持つ table_2 内のイベントを検索できます。等しいタイムスタンプ値が存在する場合は、それが最も近いものとみなされます。ここでは、user_id 列を等価結合に、ev_time 列を最も近い一致で結合するために使用できます。この例では、event_1_1 は event_2_1 と結合でき、event_1_2 は event_2_3 と結合できますが、event_2_2 は結合できません。
ASOF JOIN は hash および full_sorting_merge の結合アルゴリズムでのみサポートされています。
Join テーブルエンジンではサポートされていません。
PASTE JOIN の使用方法
PASTE JOIN の結果は、左側のサブクエリのすべてのカラムに続いて、右側のサブクエリのすべてのカラムを含むテーブルになります。
行は、元のテーブルにおける位置に基づいて対応付けられます(行の順序が定義されている必要があります)。
サブクエリが返す行数が異なる場合、余分な行は切り捨てられます。
例:
注意:この場合、読み取りが並列に行われると結果が非決定的になる可能性があります。たとえば、
分散 JOIN
分散テーブルが関わる JOIN を実行する方法は 2 つあります。
- 通常の
JOINを使用する場合、クエリはリモートサーバーに送信されます。右側のテーブルを作成するために、各サーバーでサブクエリが実行され、そのテーブルを用いて JOIN が実行されます。言い換えると、右側のテーブルは各サーバー上で個別に構築されます。 GLOBAL ... JOINを使用する場合、まずリクエスト元のサーバーがサブクエリを実行して右側のテーブルを計算します。この一時テーブルは各リモートサーバーに渡され、転送された一時データを使用してクエリが実行されます。
GLOBAL を使用する際は注意してください。詳細については、分散サブクエリ セクションを参照してください。
暗黙の型変換
INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN の各クエリでは、「結合キー」に対する暗黙の型変換がサポートされています。ただし、左側と右側のテーブルの結合キーを単一の型に変換できない場合は、クエリを実行できません(たとえば、UInt64 と Int64、あるいは String と Int32 の両方の値をすべて保持できるデータ型が存在しない場合など)。
例
次のテーブル t_1 があるとします:
およびテーブル t_2:
クエリ
次の集合を返します:
使用上の推奨事項
空セルまたは NULL セルの処理
テーブルを結合していると、空のセルが現れることがあります。設定 join_use_nulls は、ClickHouse がこれらのセルをどのように埋めるかを指定します。
JOIN キーが Nullable フィールドの場合、少なくとも 1 つのキーが NULL 値を持つ行は結合されません。
構文
USING で指定するカラムは、両方のサブクエリで同じ名前でなければなりません。それ以外のカラムは異なる名前である必要があります。サブクエリ内のカラム名を変更するには、エイリアスを使用できます。
USING 句では、結合に使用する 1 つ以上のカラムを指定し、これらのカラムが等しいことを定義します。カラムのリストはかっこなしで指定します。より複雑な結合条件はサポートされていません。
構文上の制限
1 つの SELECT クエリ内に複数の JOIN 句がある場合:
*による全カラムの取得は、サブクエリではなくテーブルを結合している場合にのみ利用できます。PREWHERE句は使用できません。USING句は使用できません。
ON、WHERE、GROUP BY 句について:
ON、WHERE、GROUP BY句では任意の式は使用できませんが、SELECT句で式を定義し、そのエイリアスを介してこれらの句で使用できます。
パフォーマンス
JOIN を実行する際、クエリの他のステージに対する実行順序の最適化は行われません。結合 (右側テーブルの検索) は、WHERE によるフィルタリングおよび集約の前に実行されます。
同じ JOIN を含むクエリを実行するたびに、結果がキャッシュされないためサブクエリは毎回再実行されます。これを避けるには、結合のために準備され、常に RAM 上に常駐している配列である特別な Join テーブルエンジンを使用します。
場合によっては、JOIN の代わりに IN を使用した方が効率的です。
ディメンションテーブルとの結合 (広告キャンペーン名などのディメンション属性を含む、比較的小さなテーブル) に JOIN が必要な場合、右側テーブルがクエリごとに再アクセスされるため、JOIN はあまり便利ではない可能性があります。そのようなケースでは、JOIN の代わりに使用すべき「dictionaries」機能があります。詳細については、Dictionaries セクションを参照してください。
メモリ制限
デフォルトでは、ClickHouse は hash join アルゴリズムを使用します。ClickHouse は right_table を取り出し、RAM 上にそのハッシュテーブルを作成します。join_algorithm = 'auto' が有効な場合、メモリ消費があるしきい値を超えると、ClickHouse は merge 結合アルゴリズムにフォールバックします。JOIN アルゴリズムの説明については、join_algorithm 設定を参照してください。
JOIN 操作のメモリ消費を制限する必要がある場合は、次の設定を使用します:
- max_rows_in_join — ハッシュテーブル内の行数を制限します。
- max_bytes_in_join — ハッシュテーブルのサイズを制限します。
これらのいずれかの制限に達した場合、ClickHouse は join_overflow_mode 設定の指示どおりに動作します。
例
例: