JOIN 절

JOIN 절

JOIN 절은 각각에 공통인 값을 사용해 하나 이상의 테이블에서 열을 결합하여 새 테이블을 생성해요. SQL을 지원하는 데이터베이스에서 흔한 연산이며 relational algebra 조인에 해당해요. 한 테이블을 조인하는 특수한 경우는 흔히 "self-join"이라고 불러요.

출처: 문서

본문

JOIN 절은 각각에 공통인 값을 사용해 하나 이상의 테이블에서 열을 결합하여 새 테이블을 생성해요. SQL을 지원하는 데이터베이스에서 흔한 연산이며 relational algebra 조인에 해당해요. 한 테이블을 조인하는 특수한 경우는 흔히 "self-join"이라고 불러요.

Syntax (구문)

SELECT <expr_list>
FROM <left_table>
[GLOBAL] [INNER|LEFT|RIGHT|FULL|CROSS] [OUTER|SEMI|ANTI|ANY|ALL|ASOF] JOIN <right_table>
(ON <expr_list>)|(USING <column_list>) ...

ON 절의 표현식과 USING 절의 열은 "조인 키(join keys)"라고 불러요. 별도 언급이 없으면 JOIN은 일치하는 "조인 키"를 가진 행들로부터 Cartesian product를 생성하며, 이는 원본 테이블보다 훨씬 많은 행을 갖는 결과를 만들 수 있어요.

Supported types of JOIN (지원되는 JOIN 유형)

모든 표준 SQL JOIN 유형이 지원돼요.

Type Description (설명)
INNER JOIN 일치하는 행만 반환돼요.
LEFT OUTER JOIN 일치하는 행에 더해 왼쪽 테이블의 비일치 행도 반환돼요.
RIGHT OUTER JOIN 일치하는 행에 더해 오른쪽 테이블의 비일치 행도 반환돼요.
FULL OUTER JOIN 일치하는 행에 더해 양쪽 테이블의 비일치 행도 반환돼요.
CROSS JOIN 전체 테이블의 카테시안 곱을 생성하며, "조인 키"는 지정되지 않아요.
NATURAL JOIN 두 테이블에서 같은 이름을 가진 모든 열에 대해 자동으로 조인해요. 각 공통 열은 결과에 한 번 나타나요. INNER(기본값), LEFT, RIGHT, FULL 변형을 지원해요. 열 목록이 자동으로 파생되는 JOIN ... USING (col1, col2, ...)과 동등해요.
  • 타입이 지정되지 않은 JOININNER를 의미해요.
  • OUTER 키워드는 안전하게 생략할 수 있어요.
  • CROSS JOIN의 대체 구문은 FROM clause에서 테이블을 쉼표로 구분해 여러 개 지정하는 것이에요.
  • NATURAL JOIN에 일치하는 열이 없으면 CROSS JOIN처럼 동작해요.

ClickHouse에서 사용 가능한 추가 조인 유형은 다음과 같아요.

Type Description (설명)
LEFT SEMI JOIN, RIGHT SEMI JOIN 카테시안 곱을 만들지 않고 "조인 키"의 허용 목록(allowlist) 역할을 해요.
LEFT ANTI JOIN, RIGHT ANTI JOIN 카테시안 곱을 만들지 않고 "조인 키"의 차단 목록(denylist) 역할을 해요.
LEFT ANY JOIN, RIGHT ANY JOIN, INNER ANY JOIN 표준 JOIN 유형에 대해 카테시안 곱을 부분적으로(LEFT와 RIGHT의 반대쪽) 또는 완전히(INNER와 FULL) 비활성화해요.
ASOF JOIN, LEFT ASOF JOIN 정확하지 않은 일치로 시퀀스를 조인해요. ASOF JOIN 사용법은 아래에 설명돼요.
PASTE JOIN 두 테이블의 수평 결합을 수행해요.

join_algorithmpartial_merge로 설정되면 RIGHT JOINFULL JOINALL 엄격성으로만 지원돼요 (SEMI, ANTI, ANY, ASOF는 지원되지 않아요).

Settings (설정)

기본 조인 유형은 join_default_strictness 설정으로 재정의할 수 있어요. ANY JOIN 연산에서 ClickHouse 서버의 동작은 any_join_distinct_right_table_keys 설정에 따라 달라져요.

See also (참고)

cross_to_inner_join_rewrite 설정을 사용해 ClickHouse가 CROSS JOININNER JOIN으로 재작성하지 못할 때의 동작을 정의할 수 있어요. 기본값은 1이며, 조인이 계속되도록 허용하지만 더 느려져요. 오류를 발생시키려면 cross_to_inner_join_rewrite0으로 설정하고, 크로스 조인을 실행하지 않고 모든 쉼표/크로스 조인의 재작성을 강제하려면 2로 설정해요. 값이 2일 때 재작성이 실패하면 "Please, try to simplify WHERE section" 오류 메시지를 받게 돼요.

ON section conditions (ON 섹션 조건)

ON 섹션은 ANDOR 연산자를 사용해 결합된 여러 조건을 포함할 수 있어요. 조인 키를 지정하는 조건은 반드시:

  • 왼쪽과 오른쪽 테이블을 모두 참조해야 하고
  • 동등 연산자(=)를 사용해야 해요

다른 조건은 다른 논리 연산자를 사용할 수 있지만 쿼리의 왼쪽 또는 오른쪽 테이블 중 하나를 참조해야 해요. 전체 복합 조건이 충족되면 행이 조인돼요. 조건이 충족되지 않으면 행은 JOIN 유형에 따라 결과에 포함될 수도 있어요. 같은 조건을 WHERE 섹션에 넣고 충족되지 않으면 행은 항상 결과에서 걸러진다는 점에 유의해요. ON 절 안의 OR 연산자는 hash join 알고리즘을 사용해 동작하며, JOIN에 대한 조인 키가 있는 각 OR 인자에 대해 별도의 해시 테이블이 생성돼요. 그래서 메모리 소비와 쿼리 실행 시간은 ON 절의 OR 표현식 수가 늘어남에 따라 선형적으로 증가해요. 조건이 다른 테이블의 열을 참조하면 지금까지는 동등 연산자(=)만 지원돼요.

Example (예제)

table_1table_2를 고려해요.

┌─Id─┬─name─┐     ┌─Id─┬─text───────────┬─scores─┐
│  1 │ A    │     │  1 │ Text A         │     10 │
│  2 │ B    │     │  1 │ Another text A │     12 │
│  3 │ C    │     │  2 │ Text B         │     15 │
└────┴──────┘     └────┴────────────────┴────────┘

하나의 조인 키 조건과 table_2에 대한 추가 조건이 있는 쿼리:

Query (쿼리)

SELECT name, text FROM table_1 LEFT OUTER JOIN table_2
    ON table_1.Id = table_2.Id AND startsWith(table_2.text, 'Text');

결과에 이름 C와 빈 text 열이 있는 행이 포함된다는 점에 유의해요. OUTER 유형의 조인이 사용되었기 때문에 결과에 포함돼요.

Response (응답)

┌─name─┬─text───┐
│ A    │ Text A │
│ B    │ Text B │
│ C    │        │
└──────┴────────┘

INNER 유형의 조인과 여러 조건이 있는 쿼리:

Query (쿼리)

SELECT name, text, scores FROM table_1 INNER JOIN table_2
    ON table_1.Id = table_2.Id AND table_2.scores > 10 AND startsWith(table_2.text, 'Text');

Response (응답)

┌─name─┬─text───┬─scores─┐
│ B    │ Text B │     15 │
└──────┴────────┴────────┘

INNER 유형의 조인과 OR 조건이 있는 쿼리:

Query (쿼리)

CREATE TABLE t1 (`a` Int64, `b` Int64) ENGINE = MergeTree() ORDER BY a;

CREATE TABLE t2 (`key` Int32, `val` Int64) ENGINE = MergeTree() ORDER BY key;

INSERT INTO t1 SELECT number as a, -a as b from numbers(5);

INSERT INTO t2 SELECT if(number % 2 == 0, toInt64(number), -number) as key, number as val from numbers(5);

SELECT a, b, val FROM t1 INNER JOIN t2 ON t1.a = t2.key OR t1.b = t2.key;

Response (응답)

┌─a─┬──b─┬─val─┐
│ 0 │  0 │   0 │
│ 1 │ -1 │   1 │
│ 2 │ -2 │   2 │
│ 3 │ -3 │   3 │
│ 4 │ -4 │   4 │
└───┴────┴─────┘

INNER 유형의 조인과 ORAND 조건이 있는 쿼리:

기본적으로 비동등 조건은 같은 테이블의 열을 사용하는 한 지원돼요. 예를 들어 t1.a = t2.key AND t1.b > 0 AND t2.b > t2.ct1.b > 0t1의 열만 사용하고 t2.b > t2.ct2의 열만 사용하기 때문이에요. 하지만 t1.a = t2.key AND t1.b > t2.key 같은 조건에 대한 실험적 지원을 시도할 수도 있어요. 자세한 내용은 아래 섹션을 참고해요.

Query (쿼리)

SELECT a, b, val FROM t1 INNER JOIN t2 ON t1.a = t2.key OR t1.b = t2.key AND t2.val > 3;

Response (응답)

┌─a─┬──b─┬─val─┐
│ 0 │  0 │   0 │
│ 2 │ -2 │   2 │
│ 4 │ -4 │   4 │
└───┴────┴─────┘

JOIN with inequality conditions for columns from different tables (다른 테이블 열에 대한 부등 조건이 있는 JOIN)

ClickHouse는 현재 동등 조건에 더해 부등 조건이 있는 ALL/ANY/SEMI/ANTI INNER/LEFT/RIGHT/FULL JOIN을 지원해요. 부등 조건은 hash, parallel_hash, grace_hash 조인 알고리즘에서만 지원돼요. 조인 중에 평가되는 비동등 조건은 행 수를 보존해야 하므로 arrayJoin을 포함할 수 없어요. 한쪽에만 적용되는 조건과 arrayJoin에 대한 동등 키는 조인 전에 추출되어 영향을 받지 않아요. 비분리(non-disjunctive) ALL INNER JOIN 조건도 조인 후에 조건이 적용되므로 영향을 받지 않아요. 확장이 한쪽에만 의존하는 경우 이를 조인 전의 서브쿼리에서 ARRAY JOIN으로 옮겨요. arrayJoin 인자가 양쪽 열을 읽는 조건은 재구성해야 해요.

Example (예제)

테이블 t1:

┌─key──┬─attr─┬─a─┬─b─┬─c─┐
│ key1 │ a    │ 1 │ 1 │ 2 │
│ key1 │ b    │ 2 │ 3 │ 2 │
│ key1 │ c    │ 3 │ 2 │ 1 │
│ key1 │ d    │ 4 │ 7 │ 2 │
│ key1 │ e    │ 5 │ 5 │ 5 │
│ key2 │ a2   │ 1 │ 1 │ 1 │
│ key4 │ f    │ 2 │ 3 │ 4 │
└──────┴──────┴───┴───┴───┘

테이블 t2

┌─key──┬─attr─┬─a─┬─b─┬─c─┐
│ key1 │ A    │ 1 │ 2 │ 1 │
│ key1 │ B    │ 2 │ 1 │ 2 │
│ key1 │ C    │ 3 │ 4 │ 5 │
│ key1 │ D    │ 4 │ 1 │ 6 │
│ key3 │ a3   │ 1 │ 1 │ 1 │
│ key4 │ F    │ 1 │ 1 │ 1 │
└──────┴──────┴───┴───┴───┘
SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON t1.key = t2.key AND (t1.a < t2.a) ORDER BY (t1.key, t1.attr, t2.key, t2.attr);
key1    a    1    1    2    key1    B    2    1    2
key1    a    1    1    2    key1    C    3    4    5
key1    a    1    1    2    key1    D    4    1    6
key1    b    2    3    2    key1    C    3    4    5
key1    b    2    3    2    key1    D    4    1    6
key1    c    3    2    1    key1    D    4    1    6
key1    d    4    7    2            0    0    \N
key1    e    5    5    5            0    0    \N
key2    a2    1    1    1            0    0    \N
key4    f    2    3    4            0    0    \N

NULL and NaN values in JOIN keys (JOIN 키의 NULL 및 NaN 값)

NULL은 자신을 포함한 어떤 값과도 같지 않아요. 즉 한 테이블의 JOIN 키가 NULL 값을 가지면 다른 테이블의 NULL 값과 일치하지 않아요.

Example (예제)

테이블 A:

┌───id─┬─name────┐
│    1 │ Alice   │
│    2 │ Bob     │
│ ᴺᵁᴸᴸ │ Charlie │
└──────┴─────────┘

테이블 B:

┌───id─┬─score─┐
│    1 │    90 │
│    3 │    85 │
│ ᴺᵁᴸᴸ │    88 │
└──────┴───────┘
SELECT A.name, B.score FROM A LEFT JOIN B ON A.id = B.id
┌─name────┬─score─┐
│ Alice   │    90 │
│ Bob     │     0 │
│ Charlie │     0 │
└─────────┴───────┘

테이블 ACharlie 행과 테이블 B의 score 88 행이 JOIN 키의 NULL 값 때문에 결과에 없음을 주목해요. NULL 값을 일치시키려면 isNotDistinctFrom 함수를 사용해 JOIN 키를 비교해요.

SELECT A.name, B.score FROM A LEFT JOIN B ON isNotDistinctFrom(A.id, B.id)
┌─name────┬─score─┐
│ Alice   │    90 │
│ Bob     │     0 │
│ Charlie │    88 │
└─────────┴───────┘

float JOIN 키의 NaN 값은 위의 NULL 규칙을 따르지 않아요. 두 NaN 값의 스칼라 비교(NaN = NaN)는 0이지만, JOIN 키는 스칼라 의미론으로 비교되지 않아요. NaN 키는 일치할 수 있어요. 실제로 일치하는지 여부는 구현 세부 사항이며 조인 알고리즘, 키 타입, 세션 설정에 따라 달라져요. 특정 동작에 의존하지 마세요. NaN 행이 일치하지 않아야 한다면 이를 NULL 값으로 매핑해요: ON if(isNaN(A.id), NULL, A.id) = B.id. ASOF JOIN에서는 최근접 일치 열을 정렬로 비교하는데 NaN은 이를 지원하지 않아요. 양쪽에서 그러한 행을 걸러내요.

ASOF JOIN usage (ASOF JOIN 사용법)

ASOF JOIN은 정확히 일치하지 않는 레코드를 조인해야 할 때 유용해요. 이 JOIN 알고리즘은 테이블에 특수 열이 필요해요. 이 열은:

  • 정렬된 시퀀스를 포함해야 하고
  • 다음 타입 중 하나일 수 있어요: Int, UInt, Float, Date, DateTime, Decimal.
  • hash 조인 알고리즘에서는 JOIN 절의 유일한 열이 될 수 없어요.

ASOF JOIN ... ON 구문:

SELECT expressions_list
FROM table_1
ASOF LEFT JOIN table_2
ON equi_cond AND closest_match_cond

임의 개수의 동등 조건과 정확히 하나의 최근접 일치 조건을 사용할 수 있어요. 예를 들어 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 구문:

SELECT expressions_list
FROM table_1
ASOF JOIN table_2
USING (equi_column1, ... equi_columnN, asof_column)

ASOF JOINequi_columnX를 동등 조인에, asof_columntable_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 JOINtable_1에서 사용자 이벤트의 타임스탬프를 가져와 table_2에서 최근접 일치 조건에 해당하는 table_1 이벤트의 타임스탬프와 가장 가까운 타임스탬프를 가진 이벤트를 찾을 수 있어요. 동일한 타임스탬프 값이 사용 가능하면 그것이 가장 가까워요. 여기서 user_id 열은 동등 조인에, ev_time 열은 최근접 일치 조인에 사용할 수 있어요. 예제에서 event_1_1event_2_1과, event_1_2event_2_3과 조인될 수 있지만 event_2_2는 조인될 수 없어요. ASOF JOINhashfull_sorting_merge 조인 알고리즘에서만 지원돼요. Join 테이블 엔진에서는 지원되지 않아요.

PASTE JOIN usage (PASTE JOIN 사용법)

PASTE JOIN의 결과는 왼쪽 서브쿼리의 모든 열 다음에 오른쪽 서브쿼리의 모든 열을 포함하는 테이블이에요. 행은 원본 테이블에서의 위치에 따라 매칭돼요(행 순서가 정의되어야 해요). 서브쿼리가 다른 수의 행을 반환하면 추가 행은 잘려요.

Example (예제):

SELECT *
FROM
(
    SELECT number AS a
    FROM numbers(2)
) AS t1
PASTE JOIN
(
    SELECT number AS a
    FROM numbers(2)
    ORDER BY a DESC
) AS t2

┌─a─┬─t2.a─┐
│ 0 │    1 │
│ 1 │    0 │
└───┴──────┘

참고: 이 경우 읽기가 병렬이면 결과가 비결정적일 수 있어요. 예를 들어:

SELECT *
FROM
(
    SELECT number AS a
    FROM numbers_mt(5)
) AS t1
PASTE JOIN
(
    SELECT number AS a
    FROM numbers(10)
    ORDER BY a DESC
) AS t2
SETTINGS max_block_size = 2;

┌─a─┬─t2.a─┐
│ 2 │    9 │
│ 3 │    8 │
└───┴──────┘
┌─a─┬─t2.a─┐
│ 0 │    7 │
│ 1 │    6 │
└───┴──────┘
┌─a─┬─t2.a─┐
│ 4 │    5 │
└───┴──────┘

Distributed JOIN (분산 JOIN)

분산 테이블이 포함된 JOIN을 실행하는 방법은 두 가지예요.

  • 일반 JOIN을 사용할 때 쿼리는 원격 서버로 전송돼요. 서브쿼리는 오른쪽 테이블을 만들기 위해 각 서버에서 실행되며, 조인은 이 테이블로 수행돼요. 즉 오른쪽 테이블은 각 서버에서 개별적으로 형성돼요.
  • GLOBAL ... JOIN을 사용할 때 요청 서버가 먼저 서브쿼리를 실행해 조인의 한쪽을 계산하고 결과를 임시 테이블에 수집해요. 그런 다음 이 임시 테이블이 각 원격 서버로 전달되고, 전송된 임시 데이터를 사용해 쿼리가 실행돼요. LEFTINNER 조인의 경우 오른쪽 테이블이 서브쿼리로 계산돼요. RIGHT 조인의 경우 오른쪽 테이블이 보존되어 샤드에서 읽혀야 하므로 왼쪽 테이블이 대신 계산돼요.

GLOBAL을 사용할 때는 주의해야 해요. 자세한 내용은 Distributed subqueries 섹션을 참고해요.

Implicit type conversion (암시적 타입 변환)

INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL JOIN 쿼리는 "조인 키"에 대한 암시적 타입 변환을 지원해요. 하지만 왼쪽과 오른쪽 테이블의 조인 키를 단일 타입으로 변환할 수 없으면 쿼리를 실행할 수 없어요(예: UInt64Int64, 또는 StringInt32의 모든 값을 담을 수 있는 데이터 타입이 없는 경우).

Example (예제)

테이블 t_1을 고려해요.

┌─a─┬─b─┬─toTypeName(a)─┬─toTypeName(b)─┐
│ 1 │ 1 │ UInt16        │ UInt8         │
│ 2 │ 2 │ UInt16        │ UInt8         │
└───┴───┴───────────────┴───────────────┘

그리고 테이블 t_2:

┌──a─┬────b─┬─toTypeName(a)─┬─toTypeName(b)───┐
│ -1 │    1 │ Int16         │ Nullable(Int64) │
│  1 │   -1 │ Int16         │ Nullable(Int64) │
│  1 │    1 │ Int16         │ Nullable(Int64) │
└────┴──────┴───────────────┴─────────────────┘

쿼리

SELECT a, b, toTypeName(a), toTypeName(b) FROM t_1 FULL JOIN t_2 USING (a, b);

는 집합을 반환해요.

┌──a─┬────b─┬─toTypeName(a)─┬─toTypeName(b)───┐
│  1 │    1 │ Int32         │ Nullable(Int64) │
│  2 │    2 │ Int32         │ Nullable(Int64) │
│ -1 │    1 │ Int32         │ Nullable(Int64) │
│  1 │   -1 │ Int32         │ Nullable(Int64) │
└────┴──────┴───────────────┴─────────────────┘

Usage recommendations (사용 권장 사항)

Processing of empty or NULL cells (빈 또는 NULL 셀 처리)

테이블을 조인할 때 빈 셀이 나타날 수 있어요. 설정 join_use_nulls은 ClickHouse가 이 셀들을 어떻게 채우는지 정의해요. JOIN 키가 Nullable 필드이면 키 중 하나라도 NULL 값을 가진 행은 조인되지 않아요.

Syntax (구문)

USING에 지정된 열은 두 서브쿼리에서 같은 이름을 가져야 하며, 다른 열은 서로 다른 이름이어야 해요. 별칭을 사용해 서브쿼리의 열 이름을 바꿀 수 있어요. USING 절은 조인할 하나 이상의 열을 지정하며, 이 열들의 동등성을 설정해요. 열 목록은 괄호 없이 설정돼요. 더 복잡한 조인 조건은 지원되지 않아요.

Syntax Limitations (구문 제한)

단일 SELECT 쿼리에서 여러 JOIN 절에 대해:

  • *로 모든 열을 가져오는 것은 테이블이 조인된 경우에만 사용할 수 있고, 서브쿼리일 때는 사용할 수 없어요.
  • PREWHERE 절은 사용할 수 없어요.
  • USING 절은 사용할 수 없어요.

ON, WHERE, GROUP BY 절에 대해:

  • ON, WHERE, GROUP BY 절에서는 임의 표현식(*)을 사용할 수 없어요. 하지만 SELECT 절에서 표현식을 정의한 뒤 별칭으로 이 절들에서 사용할 수 있어요.

Performance (성능)

JOIN을 실행할 때 쿼리의 다른 단계와 관련한 실행 순서의 최적화는 없어요. 조인(오른쪽 테이블 검색)은 WHERE의 필터링 전에, 집계 전에 실행돼요. 같은 JOIN으로 쿼리를 실행할 때마다 결과가 캐시되지 않으므로 서브쿼리가 다시 실행돼요. 이를 피하려면 항상 RAM에 있는 준비된 조인 배열인 특별한 Join 테이블 엔진을 사용해요. 어떤 경우에는 JOIN 대신 IN을 사용하는 것이 더 효율적이에요. 차원 테이블(광고 캠페인 이름 같은 차원 속성을 가진 비교적 작은 테이블)과 조인해야 한다면, 오른쪽 테이블이 매 쿼리마다 다시 접근되기 때문에 JOIN이 그리 편리하지 않을 수 있어요. 그런 경우 JOIN 대신 "dictionaries" 기능을 사용해야 해요. 자세한 내용은 Dictionaries 섹션을 참고해요.

Memory limitations (메모리 제한)

기본적으로 ClickHouse는 hash join 알고리즘을 사용해요. ClickHouse는 오른쪽 테이블을 가져와 RAM에 해시 테이블을 만들어요. join_algorithm = 'auto'가 활성화되면 메모리 소비가 일정 임계값을 넘은 뒤 ClickHouse는 merge 조인 알고리즘으로 전환해요. JOIN 알고리즘 설명은 join_algorithm 설정을 참고해요. JOIN 연산의 메모리 소비를 제한해야 한다면 다음 설정을 사용해요.

이 한도 중 하나에 도달하면 ClickHouse는 join_overflow_mode 설정이 지시한 대로 동작해요. 이 둘은 하드 캡이며 조인이 디스크로 스필(spill)되게 하지 않아요. 따라서 스필 임계값 이하(또는 같게) 설정하면 보통 쿼리가 스필되기 전에 멈추게 돼요. 이를 바꾸는 설정 두 가지가 있어요: enable_adaptive_memory_spill_scheduler는 임계값 이하에서 스필 가능하게 만든 조인을 여전히 스필시킬 수 있고, legacy_join_size_limits_trigger_spilling은 두 캡을 다시 디스크 스필 트리거로 바꿔요. 오른쪽을 실패시키는 대신 디스크로 스필시켜 조인을 계속 실행하려면 다음을 사용해요.

이들은 grace_hash를 포함한 모든 해시 기반 알고리즘의 임계값 기반 스필 트리거예요. 메모리 압박이 있으면 enable_adaptive_memory_spill_scheduler가 요청된 것보다 일찍 스필할 수 있어요. 하지만 둘 중 하나가 0이 아니어야 가능해요. 임계값이 전혀 없는 조인은 절대 스필하지 않기 때문이에요. 선택한 join_algorithm은 조인이 어떻게 스필하는지 결정해요. grace_hash는 첫 블록부터 오른쪽 테이블을 파티셔닝하고, hashparallel_hash는 메모리에 수집하다 임계값을 넘으면 전환해요. 이 설정들이 적용되는지 여부와는 무관해요. 유일한 예외는 legacy_join_size_limits_trigger_spilling인데, 켜면 단독 grace_hash가 두 임계값을 무시하고 두 하드 캡에서 스필해요.

Examples (예제)

Example (예제):

SELECT
    CounterID,
    hits,
    visits
FROM
(
    SELECT
        CounterID,
        count() AS hits
    FROM test.hits
    GROUP BY CounterID
) ANY LEFT JOIN
(
    SELECT
        CounterID,
        sum(Sign) AS visits
    FROM test.visits
    GROUP BY CounterID
) USING CounterID
ORDER BY hits DESC
LIMIT 10
┌─CounterID─┬───hits─┬─visits─┐
│   1143050 │ 523264 │  13665 │
│    731962 │ 475698 │ 102716 │
│    722545 │ 337212 │ 108187 │
│    722889 │ 252197 │  10547 │
│   2237260 │ 196036 │   9522 │
│  23057320 │ 147211 │   7689 │
│    722818 │  90109 │  17847 │
│     48221 │  85379 │   4652 │
│  19762435 │  77807 │   7026 │
│    722884 │  77492 │  11056 │
└───────────┴────────┴────────┘

더 알아보기 (Learn more)