조인 범위 최적화

범위 조인은 두 값이 같은지 확인하는 대신, 값이 범위 내에 속하는지, 두 범위가 겹치는지 확인하는 조건으로 두 테이블을 연결합니다. 예를 들어, 각 웹사이트 이벤트를 사용자 세션과 매칭하는 쿼리는 이벤트의 타임스탬프가 세션의 시작과 종료 시간 사이에 위치하는지 확인합니다. 같은 시간에 예정된 회의를 찾는 쿼리는 두 시간 범위가 겹치는지 확인합니다. Databricks Runtime의 범위 조인 최적화는 이러한 쿼리의 성능을 크게 향상시킬 수 있습니다.

이 때문에 조인은 일치할 수 없는 여러 행 쌍을 비교할 수 있습니다. 범위 조인 최적화는 값의 범위를 빈 으로 나누고, 겹치는 빈에 속하는 행만을 비교합니다. 빈 크기를 참조하세요.

Databricks SQL에서 Azure Databricks 수동 구성 없이 범위 조인을 자동으로 최적화합니다. 모든 컴퓨팅 유형에 대해 조인 힌트 또는 세션 구성을 사용하여 범위 조인을 수동으로 조정할 수도 있습니다.

점 간격 범위 조인

간격 범위 조인의 한 지점은 조건에 한 관계의 값이 다른 관계의 두 값 사이에 있음을 지정하는 조건자를 포함하는 조인입니다. 예시:

-- using BETWEEN expressions
SELECT *
FROM points JOIN ranges ON points.p BETWEEN ranges.start and ranges.end;

-- using inequality expressions
SELECT *
FROM points JOIN ranges ON points.p >= ranges.start AND points.p < ranges.end;

-- with fixed length interval
SELECT *
FROM points JOIN ranges ON points.p >= ranges.start AND points.p < ranges.start + 100;

-- join two sets of point values within a fixed distance from each other
SELECT *
FROM points1 p1 JOIN points2 p2 ON p1.p >= p2.p - 10 AND p1.p <= p2.p + 10;

-- a range condition together with other join conditions
SELECT *
FROM points, ranges
WHERE points.symbol = ranges.symbol
  AND points.p >= ranges.start
  AND points.p < ranges.end;

간격 겹침 범위 조인

간격 겹침 범위 조인은 각 관계의 두 값 사이의 간격이 겹치는지 확인하는 조건자를 포함한 조인입니다. 예시:

-- overlap of [r1.start, r1.end] with [r2.start, r2.end]
SELECT *
FROM r1 JOIN r2 ON r1.start < r2.end AND r2.start < r1.end;

-- overlap of fixed length intervals
SELECT *
FROM r1 JOIN r2 ON r1.start < r2.start + 100 AND r2.start < r1.start + 100;

-- a range condition together with other join conditions
SELECT *
FROM r1 JOIN r2 ON r1.symbol = r2.symbol
  AND r1.start <= r2.end
  AND r1.end >= r2.start;

조인 범위 최적화

범위 조인 최적화는 다음과 같은 조인에 적용됩니다:

  • 점-구간 또는 구간 중첩 범위 조인 조건
  • 범위 조인 조건에서는 숫자(정수, 부동 소수점 또는 10진수), DATE, 또는 TIMESTAMP 값만 사용하세요.
  • 범위 조인 조건에서 같은 유형의 값을 사용하세요. 십진수 역시 동일한 소수 자릿수와 정밀도를 가져야 합니다.
  • 지원되는 조인 타입을 사용하세요:
    • INNER JOIN, 임의의 범위 결합에 대해
    • LEFT OUTER JOIN에서 점 값이 왼쪽에 있거나 RIGHT OUTER JOIN에서 점 값이 오른쪽에 있는 경우, point-in-interval range join에만 해당
  • 빈 크기를 자동으로 생성하거나 수동으로 지정하세요.

숫자 같음 및 범위 조건을 사용하는 조인

조인 조건에 숫자 열의 같음 조건과 범위 조건이 모두 포함된 경우 최적화 프로그램은 범위 조인 최적화에 대한 형식 요구 사항을 충족하므로 숫자 같음 열에 범주화를 적용할 수 있습니다. 이로 인해 같음 열이 bin에 할당되거나 최적화에서 제외되어 성능이 저하될 수 있습니다.

범위 조인 최적화가 의도한 범위 조건에만 적용되도록 하려면 숫자 같음 열을 .로 캐스팅합니다 STRING. 이렇게 하면 범위 조건 열로 고려할 때 제외됩니다.

SELECT /*+ RANGE_JOIN(reference, 3306084) */
    reference.*, position.*
FROM position
INNER JOIN reference
    ON CAST(position.parent_index AS STRING) = CAST(reference.parent_index AS STRING)
    AND position.child_index BETWEEN reference.min_child_index AND reference.max_child_index;

같은 패턴은 같음 키로 사용되는 다른 숫자 열(예: DATE정수 식별자 또는 클러스터형 파티션 열)에 적용됩니다.

상자 크기

bin 크기은 범위 조건의 값 도메인을 동일한 크기의 여러 bin으로 나누는 숫자 튜닝 매개변수입니다. 예를 들어, bin 크기가 10인 경우 최적화는 도메인을 길이가 10인 간격인 bin으로 분할합니다. p BETWEEN start AND end의 범위 조건에 포인트가 있고 start가 8이고 end가 22인 경우 이 값 간격은 길이가 10인 3개의 bin(0에서 10까지의 첫 번째 bin, 10에서 20까지의 두 번째 bin, 20에서 30까지의 세 번째 bin)과 겹칩니다. 동일한 세 개의 bin 내에 속하는 지점만 해당 간격에 대해 가능한 조인 일치 항목으로 간주해야 합니다. 예를 들어, p가 32인 경우 30에서 40 사이의 bin에 속하므로 start가 8이고 end가 22인 사이에 속하는 것으로 배제할 수 있습니다.

참고

  • DATE 값의 경우 bin 크기의 값은 일로 간주됩니다. 예를 들어, bin 크기 값이 7이면 일주일을 나타냅니다.
  • TIMESTAMP 값의 경우 bin 크기의 값은 초로 해석됩니다. 1초 미만 값에는 분수 값을 사용하세요. 예를 들어, bin 크기 값이 60이면 1분을 나타내고 bin 크기 값이 0.1이면 100밀리초를 나타냅니다.

쿼리에서 범위 조인 힌트를 사용하거나 세션 구성 매개 변수를 설정하여 bin 크기를 지정할 수 있습니다. Databricks SQL에서 bin 크기는 자동 범위 조인 최적화를 사용하도록 설정하면 자동으로 파생됩니다.

자동 범위 조인 최적화

Databricks SQL에서 Azure Databricks 자동으로 적격 범위 조인을 검색하고 간격 테이블을 샘플링하여 최적의 bin 크기를 파생합니다. 이렇게 하면 힌트 또는 세션 구성을 통해 bin 크기를 수동으로 지정할 필요가 없습니다.

자동 범위 조인 최적화는 기본적으로 Databricks SQL에서 사용하도록 설정됩니다. 비활성화하려면 다음 구성을 설정하세요:

SET spark.databricks.optimizer.autoRangeJoin.enabled = false;

범위 조인 힌트 또는 세션 구성을 통해 bin 크기를 지정하면 해당 값이 자동으로 결정된 bin 크기보다 우선 적용됩니다.

범위 조인 힌트를 사용하여 범위 조인을 활성화합니다.

SQL 쿼리에서 범위 조인 최적화를 사용하도록 설정하려면 범위 조인 힌트 를 사용하여 bin 크기를 지정합니다. 힌트는 조인된 관계 중 하나의 관계 이름과 숫자 bin 크기 매개 변수를 포함해야 합니다. 관계 이름은 테이블, 뷰 또는 서브쿼리를 가리킵니다.

SELECT /*+ RANGE_JOIN(points, 10) */ *
FROM points JOIN ranges ON points.p >= ranges.start AND points.p < ranges.end;

SELECT /*+ RANGE_JOIN(r1, 0.1) */ *
FROM (SELECT * FROM ranges WHERE ranges.amount < 100) r1, ranges r2
WHERE r1.start < r2.start + 100 AND r2.start < r1.start + 100;

SELECT /*+ RANGE_JOIN(c, 500) */ *
FROM a
  JOIN b ON (a.b_key = b.id)
  JOIN c ON (a.ts BETWEEN c.start_time AND c.end_time)

참고

세 번째 예제에서는 힌트를 반드시c에 놓아야 합니다. 조인은 연관성이 남아 있으므로 쿼리가 (a JOIN b) JOIN c해석되고 a 대한 힌트는 a조인이 아닌 bc 조인에 적용되기 때문입니다.

#create minute table
minutes = spark.createDataFrame(
    [(0, 60), (60, 120)],
    "minute_start: int, minute_end: int"
)

#create events table
events = spark.createDataFrame(
    [(12, 33), (0, 120), (33, 72), (65, 178)],
    "event_start: int, event_end: int"
)

#Range_Join with "hint" on the from table
(events.hint("range_join", 60)
  .join(minutes,
    on=[events.event_start < minutes.minute_end,
    minutes.minute_start < events.event_end])
  .orderBy(events.event_start,
    events.event_end,
    minutes.minute_start)
  .show()
)

#Range_Join with "hint" on the join table
(events.join(minutes.hint("range_join", 60),
  on=[events.event_start < minutes.minute_end,
    minutes.minute_start < events.event_end])
  .orderBy(events.event_start,
    events.event_end,
    minutes.minute_start)
  .show()
)

조인된 DataFrames 중 하나에 범위 조인 힌트를 배치할 수도 있습니다. 이 경우 힌트에는 숫자 bin 크기 매개 변수만 포함됩니다.

val df1 = spark.table("ranges").as("left")
val df2 = spark.table("ranges").as("right")

val joined = df1.hint("range_join", 10)
  .join(df2, $"left.type" === $"right.type" &&
     $"left.end" > $"right.start" &&
     $"left.start" < $"right.end")

val joined2 = df1
  .join(df2.hint("range_join", 0.5), $"left.type" === $"right.type" &&
     $"left.end" > $"right.start" &&
     $"left.start" < $"right.end")

세션 구성을 통해 범위 조인을 활성화합니다.

쿼리를 수정하지 않으려면 bin 크기를 구성 매개 변수로 지정합니다.

SET spark.databricks.optimizer.rangeJoin.binSize=5

이 구성 매개 변수는 범위 조건이 있는 모든 조인에 적용됩니다. 그러나 범위 조인 힌트를 통해 설정된 다른 bin 크기는 매개 변수를 통해 설정된 값을 항상 덮어씁니다.

bin 크기 선택

범위 조인 최적화의 효과는 적절한 bin 크기를 선택하는 데 따라 달라집니다.

Bin 크기가 작으면 더 많은 수의 bin이 생성되어 잠재적인 일치 항목을 필터링하는 데 도움이 됩니다. 작은 빈 크기는 값 구간이 빈 크기보다 훨씬 커서 구간이 여러 빈에 겹치면 비효율적이 됩니다. 예를 들어, end 조건에서 p BETWEEN start AND end이 1,000,000이고 start가 1,999,999이며 빈 크기가 10이면, 해당 구간은 100,000개의 빈과 겹칩니다.

구간 길이가 비교적 균일하고 알려져 있다면, 빈 크기를 일반적인 구간 길이로 설정하세요. 다양하고 왜곡된 구간의 경우, 짧은 구간을 효율적으로 필터링하면서도 긴 구간이 너무 많은 빈과 겹치지 않도록 하는 빈 크기를 선택하세요. 열 end 및 ranges 사이에 구간이 있는 표 start의 경우, 이 쿼리로 왜곡된 구간 길이의 백분위수를 구합니다:

SELECT
  map_from_arrays(
    ARRAY(0.5, 0.9, 0.99, 0.999, 0.9999),
    APPROX_PERCENTILE(
      end::DOUBLE - start::DOUBLE,
      ARRAY(0.5, 0.9, 0.99, 0.999, 0.9999)
    )
  ) AS bin_sizes
FROM
  ranges;

빼기 전에 각 열을 DOUBLE로 캐스팅하면 열 값이 숫자이든, DATE 값이든, TIMESTAMP 값이든 관계없이 쿼리가 작동합니다.

빈 크기를 이 값들 중 가장 큰 값으로 설정하세요:

  • 간격 길이의 90번째 백분위수입니다. 이 크기에서는 최대 10%의 구간이 2개를 초과하는 빈을 가로지릅니다.
  • 99번째 백분위수를 10으로 나눈 값 이 크기에서는 구간의 최대 1%만 11개 빈 이상을 가로지릅니다.
  • 100으로 나눈 99.9백분위수 이 크기에서는 구간 중 최대 0.1%만 101개가 넘는 빈에 걸쳐 있습니다.

더 긴 간격을 제한하려면 99.99백분위수와 99.999백분위수로 패턴을 이어가세요. 결과를 출발점으로 삼고, 작업 부하에 맞게 빈 크기를 조정하세요.