JOIN句
JOINは、1つまたは複数のテーブルから共通の値を使用してカラムを結合することで新しいテーブルを生成します。これは、SQLをサポートするデータベースにおける一般的な操作であり、関係代数のJOINに相当します。1つのテーブルのJOINの特別なケースは、一般的に「自己結合」と呼ばれます。
構文
ON
句の式およびUSING
句のカラムは「結合キー」と呼ばれます。特に指定がない限り、JOINは「結合キー」が一致する行からのデカルト積を生成し、これによりソーステーブルよりもはるかに多くの行を持つ結果が生成される可能性があります。
関連コンテンツ
- ブログ: ClickHouse: 完全SQL JOINサポートの驚異的に高速なDBMS - パート1
- ブログ: ClickHouse: 完全SQL JOINサポートの驚異的に高速なDBMS - 内部の仕組み - パート2
- ブログ: ClickHouse: 完全SQL JOINサポートの驚異的に高速なDBMS - 内部の仕組み - パート3
- ブログ: ClickHouse: 完全SQL JOINサポートの驚異的に高速なDBMS - 内部の仕組み - パート4
サポートされているJOINの種類
すべての標準SQL JOINタイプがサポートされています:
INNER JOIN
、一致する行のみが返されます。LEFT OUTER JOIN
、左テーブルから一致する行に加えて、非一致の行も返されます。RIGHT OUTER JOIN
、右テーブルから一致する行に加えて、非一致の行も返されます。FULL OUTER JOIN
、両方のテーブルから一致する行に加えて、非一致の行も返されます。CROSS JOIN
、全テーブルのデカルト積を生成し、「結合キー」は指定されません。
指定されたタイプなしのJOIN
はINNER
を意味します。キーワードOUTER
は安全に省略できます。CROSS JOIN
の代替構文は、FROM句でカンマで区切った複数のテーブルを指定することです。
ClickHouseで使用可能な追加のJOINタイプ:
LEFT SEMI JOIN
およびRIGHT SEMI JOIN
、デカルト積を生成せずに「結合キー」のホワイトリスト。LEFT ANTI JOIN
およびRIGHT ANTI JOIN
、デカルト積を生成せずに「結合キー」のブラックリスト。LEFT ANY JOIN
、RIGHT ANY JOIN
およびINNER ANY JOIN
、デカルト積を部分的(LEFT
とRIGHT
の反対側の場合)または完全に(INNER
とFULL
の場合)無効にします。ASOF JOIN
およびLEFT ASOF JOIN
、厳密には一致しないシーケンスを結合します。ASOF JOIN
の使用は以下に示されています。PASTE JOIN
、二つのテーブルの水平方向の連結を行います。
join_algorithmがpartial_merge
に設定されている場合、RIGHT JOIN
およびFULL JOIN
はALL
の厳密度でのみサポートされています(SEMI
、ANTI
、ANY
およびASOF
はサポートされていません)。
設定
デフォルトのJOINタイプは、join_default_strictness設定を使用してオーバーライドできます。
ANY JOIN
操作におけるClickHouseサーバーの動作は、any_join_distinct_right_table_keys設定に依存します。
参考
- join_algorithm
- join_any_take_last_row
- join_use_nulls
- partial_merge_join_rows_in_right_blocks
- join_on_disk_max_files_to_merge
- any_join_distinct_right_table_keys
cross_to_inner_join_rewrite
設定を使用して、ClickHouseがCROSS JOIN
をINNER JOIN
として書き換えられなかった場合の動作を定義します。デフォルト値は1
で、これによりJOINが続行されますが、遅くなります。エラーをスローさせたい場合はcross_to_inner_join_rewrite
を0
に設定し、全てのカンマ/CROSS JOINの書き換えを強制するには2
に設定します。値が2
のときに書き換えが失敗すると、「WHERE
セクションを簡素化してください」というエラーメッセージが表示されます。
ONセクション条件
ON
セクションには、AND
およびOR
演算子を使用して結合された複数の条件を含めることができます。結合キーを指定する条件は、左側と右側の両方のテーブルを参照しなければならず、等号演算子を使用する必要があります。他の条件は別の論理演算子を使用できますが、クエリの左側または右側のテーブルのいずれかを参照する必要があります。
複合条件全体が満たされている場合に行が結合されます。条件が満たされない場合でも、JOIN
タイプに応じて結果に行が含まれる場合があります。同じ条件がWHERE
セクションに配置されていて、満たされない場合は、行は常に結果からフィルタリングされます。
ON
句内のOR
演算子は、ハッシュ結合アルゴリズムを使用して機能します。JOIN
の結合キーに対する各OR
引数に対して別々のハッシュテーブルが作成されるため、メモリ消費量とクエリ実行時間は、ON
句のOR
表現の数の増加に伴って線形に増加します。
異なるテーブルからカラムを参照する条件がある場合、現時点では等号演算子(=
)のみがサポートされています。
例
table_1
とtable_2
を考えます:
1つの結合キー条件とtable_2
に対する追加条件を持つクエリ:
結果には、名前がC
でテキストカラムが空の行が含まれます。これは、OUTER
タイプのJOINが使用されているため、結果に含まれます。
INNER
タイプのJOINと複数の条件を持つクエリ:
結果:
INNER
タイプのJOINおよびOR
を含む条件のクエリ:
結果:
INNER
タイプのJOINおよび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_use_nulls
では不等条件はサポートされていません。
例
テーブルt1
:
テーブルt2
:
JOINキーのNULL値
NULLは任意の値、自己すら等しくありません。これは、JOINキーが一方のテーブルにNULLの値を持っている場合、他方のテーブルのNULL値と一致しないことを意味します。
例
テーブルA
:
テーブルB
:
JOINキーにNULL値があるため、テーブルA
のCharlie
の行とテーブルB
のスコア88の行は結果に含まれていないことに注意してください。
NULL値を一致させたい場合は、isNotDistinctFrom
関数を使用してJOINキーを比較してください。
ASOF JOINの使用法
ASOF JOIN
は、正確な一致がないレコードを結合する必要がある場合に便利です。
このアルゴリズムには、テーブル内の特別なカラムが必要です。このカラムは:
- 順序されたシーケンスを含む必要があります。
- 以下のいずれかのタイプであることができます: Int, UInt、Float、Date、DateTime、Decimal。
hash
結合アルゴリズムの場合、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
を使用し、最も近い一致のためにasof_column
を使用します。この場合、table_1.asof_column >= table_2.asof_column
条件が必要です。asof_column
カラムは常にUSING
句の最後にあります。
以下のテーブルを考えてみましょう:
table_1 table_2 event | ev_time | user_id event | ev_time | user_id ----------|---------|---------- ----------|---------|---------- ... ... event_1_1 | 12:00 | 42 event_2_1 | 11:59 | 42 ... event_2_2 | 12:30 | 42 event_1_2 | 13:00 | 42 event_2_3 | 13:00 | 42 ... ...
ASOF JOIN
は、table_1
のユーザーイベントのタイムスタンプを取り、最も近い一致条件に該当する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
句は、結合に複数のカラムを指定し、これによりこれらのカラムの等式を確立します。カラムのリストは括弧なしで設定されます。より複雑な結合条件はサポートされていません。
構文の制限
単一のSELECT
クエリ内で複数のJOIN
句がある場合:
*
を介してすべてのカラムを取得することは、テーブルが結合されている場合のみ利用できます。サブクエリは含まれません。PREWHERE
句は利用できません。USING
句は利用できません。
ON
、 WHERE
、および GROUP BY
句の場合:
ON
、WHERE
、およびGROUP BY
句で任意の表現を使用できませんが、SELECT
句で表現を定義し、エイリアスを介してそれをこれらの句で使用できます。
パフォーマンス
JOIN
を実行するとき、他のクエリステージに対する実行順序の最適化は行われません。JOIN(右側のテーブルの検索)は、WHERE
でのフィルタリングおよび集約の前に実行されます。
同じJOIN
でクエリが実行されるたびに、サブクエリは再度実行されます。結果はキャッシュされません。これを避けるには、常にRAM内にあるJOIN用の準備された配列である特別なJoinテーブルエンジンを使用してください。
場合によっては、JOIN
ではなく、INを使用する方が効率的です。
次元テーブル(これらは、広告キャンペーンの名前などの次元特性を含む比較的小さなテーブル)との結合にJOIN
が必要な場合、右側のテーブルがすべてのクエリに対して再アクセスされるため、JOIN
はそれほど便利ではないかもしれません。そのような場合には、JOIN
の代わりに「辞書」機能を使用することをお勧めします。詳細については、辞書セクションを参照してください。
メモリ制限
デフォルトでは、ClickHouseはハッシュJOINアルゴリズムを使用します。ClickHouseは右側のテーブルを取り、それに対してRAM内にハッシュテーブルを作成します。join_algorithm = 'auto'
が有効になっている場合、一部のメモリ消費の閾値を超えると、ClickHouseはマージ結合アルゴリズムに戻ります。JOIN
アルゴリズムの説明については、join_algorithm設定を参照してください。
JOIN
操作のメモリ消費を制限する必要がある場合は、次の設定を使用してください:
- max_rows_in_join — ハッシュテーブル内の行数の制限。
- max_bytes_in_join — ハッシュテーブルのサイズの制限。
これらのいずれかの制限に達すると、ClickHouseはjoin_overflow_mode設定に従って動作します。
例
例: