다음을 통해 공유


적응형 쿼리 실행

적응 쿼리 실행 (AQE)은 쿼리 실행 중에 발생하는 쿼리의 재최적화입니다.

런타임 다시 최적화의 동기는 Azure Databricks가 순서 섞기 및 브로드캐스트 교환(AQE의 쿼리 단계라고 함)이 끝날 때 가장 up-to정확한 통계를 가지고 있다는 것입니다. 따라서 Azure Databricks는 더 나은 물리적 전략을 선택하거나, 최적의 셔플 이후 파티션 크기와 수를 선택하거나, 힌트를 필요로 했던 최적화(예: 편향 조인 처리)를 수행할 수 있습니다.

통계 수집이 설정되지 않거나 통계가 부실할 때 매우 유용할 수 있습니다. 또한 복잡한 쿼리의 중간이나 데이터 불균형이 발생한 후와 같이 정적으로 산출된 통계가 부정확한 곳에서도 유용합니다.

기능

AQE는 기본적으로 사용하도록 설정됩니다. 다음과 같은 4가지 주요 기능이 있습니다.

  • 정렬 병합 조인을 브로드캐스트 해시 조인으로 동적으로 변경합니다.
  • 셔플 교환 후 작은 파티션을 적절한 크기로 병합하여 파티션을 동적으로 결합합니다. 매우 작은 작업은 I/O 처리량이 더 낮고, 스케줄링 오버헤드 및 작업 설정 오버헤드로 인해 더 큰 영향을 받는 경향이 있습니다. 작은 작업을 결합하면 리소스가 절약되고 클러스터 처리량이 향상됩니다.
  • 정렬 병합 조인과 셔플 해시 조인에서 왜곡된 작업을 필요에 따라 복제하여 대략적으로 균등한 크기의 작업으로 분할하여 동적으로 처리합니다.
  • 빈 관계를 동적으로 검색하고 전파합니다.

신청

AQE는 다음과 같은 모든 쿼리에 적용됩니다.

  • 비 스트리밍
  • 하나 이상의 교환(일반적으로 조인, 집계 또는 창이 있는 경우), 하나의 하위 쿼리 또는 둘 다를 포함합니다.

모든 AQE 적용 쿼리가 반드시 다시 최적화되는 것은 아닙니다. 다시 최적화는 정적으로 컴파일된 쿼리 계획과 다른 쿼리 계획을 만들 수도 있고 그렇지 않을 수도 있습니다. AQE에서 쿼리 계획이 변경되었는지 여부를 확인하려면 다음 섹션 쿼리 계획을 참조하세요.

쿼리 계획

이 섹션에서는 쿼리 계획을 다양한 방식으로 검사하는 방법에 대해 설명합니다.

이 섹션에서는 다음을 수행합니다.

Spark 사용자 인터페이스 (UI)

AdaptiveSparkPlan 노드

AQE 적용 쿼리에는 일반적으로 각 주 쿼리 또는 하위 쿼리의 루트 노드인 하나 이상의 AdaptiveSparkPlan 노드가 포함됩니다. 쿼리가 실행되기 전에 또는 실행 중일 때 해당 isFinalPlan 노드의 AdaptiveSparkPlan 플래그는 false;로 표시됩니다. 쿼리 실행이 완료되면 isFinalPlan 플래그가 true. 변경됩니다.

진화하는 계획

쿼리 계획 다이어그램은 실행이 진행됨에 따라 진화하고 실행 중인 최신 계획을 반영합니다. 이미 실행되어 메트릭이 있는 노드는 변경되지 않지만, 아직 실행되지 않은 노드는 다시 최적화되면서 시간이 지남에 따라 변경될 수 있습니다.

다음은 쿼리 계획 다이어그램 예제입니다.

쿼리 계획 다이어그램

DataFrame.explain()

AdaptiveSparkPlan 노드

AQE 적용 쿼리에는 일반적으로 각 주 쿼리 또는 하위 쿼리의 루트 노드인 하나 이상의 AdaptiveSparkPlan 노드가 포함됩니다. 쿼리가 실행되기 전에 또는 실행 중일 때 해당 isFinalPlan 노드의 AdaptiveSparkPlan 플래그는 false;로 표시됩니다. 쿼리 실행이 완료되면 isFinalPlan 플래그가 true변경됩니다.

현재 및 초기 계획

AdaptiveSparkPlan 노드에는 실행이 완료되었는지 여부에 따라 초기 계획(AQE 최적화를 적용하기 전의 계획)과 현재 또는 최종 계획이 모두 있습니다. 현재 계획은 실행이 진행됨에 따라 진화합니다.

실행 시간 통계

각 셔플 및 브로드캐스트 스테이지에는 데이터 통계가 포함됩니다.

스테이지가 실행되기 전이나, 스테이지가 실행 중일 때 통계는 컴파일 시간 예상치이며, 플래그 isRuntimefalse로 설정됩니다(예: Statistics(sizeInBytes=1024.0 KiB, rowCount=4, isRuntime=false);).

스테이지 실행이 완료되면, 통계는 런타임에 수집되며, 플래그 isRuntimetrue로 변경됩니다(예: Statistics(sizeInBytes=658.1 KiB, rowCount=2.81E+4, isRuntime=true)).

다음은 DataFrame.explain 예제입니다.

  • 실행 전

    실행 전

  • 실행 중

    실행 중

  • 실행 후

    실행 후

SQL EXPLAIN

AdaptiveSparkPlan 노드

AQE 적용 쿼리에는 일반적으로 각 주 쿼리 또는 하위 쿼리의 루트 노드인 하나 이상의 AdaptiveSparkPlan 노드가 포함됩니다.

현재 계획 없음

SQL EXPLAIN 쿼리를 실행하지 않으므로 현재 계획은 항상 초기 계획과 동일하며 결국 AQE에서 실행되는 것을 반영하지 않습니다.

다음은 SQL 설명 예제입니다.

SQL 설명

효과

하나 이상의 AQE 최적화가 적용되면 쿼리 계획이 변경됩니다. 이러한 AQE 최적화의 효과는 현재 및 최종 계획과 초기 계획과 현재 및 최종 계획의 특정 계획 노드 간의 차이에 의해 입증됩니다.

  • 동적으로 정렬된 머지 조인을 브로드캐스트 해시 조인으로 변경: 초기 계획 및 현재/최종 계획 간의 물리적 조인 노드 차이

    조인 전략 문자열

  • 동적으로 파티션 통합: 노드 CustomShuffleReader 속성 Coalesced

    사용자 지정 순서 섞기 판독기

    사용자 지정 순서 섞기 판독기 문자열

  • 동적으로 기울임 조인 처리: 필드 SortMergeJoin이 true인 노드 isSkew.

    스큐 조인 계획

    스큐 조인 문자열

  • 빈 관계를 동적으로 검색하고 전파합니다. 계획의 일부(또는 전체)는 관계 필드가 비어 있는 Node LocalTableScan으로 대체됩니다.

    로컬 테이블 검사

    로컬 테이블 검색 문자열

구성

이 섹션에서는 다음을 수행합니다.

적응형 쿼리 실행 사용 및 사용 안 함

재산
spark.databricks.optimizer.adaptive.enabled

형식: Boolean

적응형 쿼리 실행을 사용하거나 사용하지 않도록 설정할지 여부입니다.

기본값: true

자동 최적화 섞기 활성화

재산
spark.sql.shuffle.partitions

형식: Integer

조인 또는 집계에 대한 데이터를 섞을 때 사용할 기본 파티션 수입니다. auto 값을 설정하면 자동 최적화 순서 섞기가 가능하며, 쿼리 계획 및 쿼리 입력 데이터 크기에 따라 이 숫자가 자동으로 결정됩니다.

참고: 구조적 스트리밍의 경우 동일한 검사점 위치에서 쿼리를 다시 시작하는 사이에 이 구성을 변경할 수 없습니다.

기본값: 200

동적으로 정렬 합병 조인을 브로드캐스트 해시 조인으로 변경

재산
spark.databricks.adaptive.autoBroadcastJoinThreshold

형식: Byte String

런타임에 브로드캐스트 조인으로 전환을 트리거하는 임계값입니다.

기본값: 30MB

동적으로 파티션을 결합하다

재산
spark.sql.adaptive.coalescePartitions.enabled

형식: Boolean

파티션 병합을 사용하거나 사용하지 않도록 설정할지 여부입니다.

기본값: true
spark.sql.adaptive.advisoryPartitionSizeInBytes

형식: Byte String

병합 후의 대상 크기입니다. 병합된 파티션 크기는 이 대상 크기에 가깝지만 더 크지는 않습니다.

기본값: 64MB
spark.sql.adaptive.coalescePartitions.minPartitionSize

형식: Byte String

병합 후 파티션의 최소 크기입니다. 병합된 파티션 크기는 이 크기보다 작지 않습니다.

기본값: 1MB
spark.sql.adaptive.coalescePartitions.minPartitionNum

형식: Integer

병합 후의 최소 파티션 수입니다. 설정이 명시적으로 재정의되므로 권장되지 않습니다.
spark.sql.adaptive.coalescePartitions.minPartitionSize.

기본값: 클러스터 코어 수의 2배

동적으로 불균형 조인 처리

재산
spark.sql.adaptive.skewJoin.enabled

형식: Boolean

기울이기 조인 처리를 사용하거나 사용하지 않도록 설정할지 여부입니다.

기본값: true
spark.sql.adaptive.skewJoin.skewedPartitionFactor

형식: Integer

중간 파티션 크기를 곱하면 파티션이 기울어지는지 여부를 결정하는 요인이 됩니다.

기본값: 5
spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes

형식: Byte String

파티션이 기울어지는지 여부를 결정하는 데 기여하는 임계값입니다.

기본값: 256MB

파티션은 (partition size > skewedPartitionFactor * median partition size)(partition size > skewedPartitionThresholdInBytes)이 둘 다 true일 때 기울어진 것으로 간주됩니다.

빈 관계를 동적으로 검색 및 전파

재산
spark.databricks.adaptive.emptyRelationPropagation.enabled

형식: Boolean

동적 빈 관계 전파를 사용하거나 사용하지 않도록 설정할지 여부입니다.

기본값: true

FAQ(질문과 대답)

이 섹션에서는 다음을 수행합니다.

AQE에서 작은 조인 테이블을 브로드캐스트하지 않은 이유는 무엇인가요?

전송될 것으로 예상되는 관계의 크기가 임계값에 도달하지만 여전히 전송되지 않는 경우:

  • 조인 유형을 확인합니다. 브로드캐스트는 특정 조인 형식에 대해 지원되지 않습니다. 예를 들어 LEFT OUTER JOIN 왼쪽 관계는 브로드캐스트할 수 없습니다.
  • 관계가 많은 빈 파티션을 포함할 수도 있습니다. 이 경우, 작업의 대부분이 정렬 병합 조인을 통해 빠르게 완료되거나 기울기 조인 처리를 통해 최적화될 수 있습니다. 비어있지 않은 파티션의 비율이 spark.sql.adaptive.nonEmptyPartitionRatioForBroadcastJoin미만인 경우 AQE는 이러한 정렬 병합 조인을 브로드캐스트 해시 조인으로 변경하지 않습니다.

AQE가 활성화된 상태에서 브로드캐스트 조인 전략 힌트를 여전히 사용해야 하나요?

예. 정적으로 계획된 브로드캐스트 조인은 일반적으로 AQE가 동적으로 계획한 브로드캐스트 조인보다 성능이 더 높습니다. AQE는 조인의 양쪽에 대해 셔플을 수행한 후 실제 관계의 크기를 얻은 이후에야 브로드캐스트 조인으로 전환할 수도 있습니다. 따라서 쿼리를 잘 알고 있는 경우에도 브로드캐스트 힌트를 사용하는 것이 좋습니다. AQE는 정적 최적화와 동일한 방식으로 쿼리 힌트를 준수하지만 힌트의 영향을 받지 않는 동적 최적화를 적용할 수 있습니다.

스큐 조인 힌트와 AQE 스큐 조인 최적화의 차이점은 무엇인가요? 어떤 것을 사용해야 하나요?

AQE 기울이기 조인은 완전히 자동이며 일반적으로 힌트에 비해 더 잘 수행되므로 기울이기 조인 힌트를 사용하는 대신 AQE 기울이기 조인 처리를 사용하는 것이 좋습니다.

AQE에서 조인 순서를 자동으로 조정하지 않은 이유는 무엇인가요?

동적 조인 다시 정렬은 AQE의 일부가 아닙니다.

AQE에서 내 데이터 기울이기를 감지하지 못한 이유는 무엇인가요?

AQE가 파티션을 왜곡된 파티션으로 검색하려면 다음 두 가지 크기 조건을 충족해야 합니다.

  • 파티션 크기가 spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes(기본값 256MB)보다 큽니다.
  • 파티션 크기가 모든 파티션의 중위수 크기보다 크며, 이 크기는 기울어진 파티션 요소 spark.sql.adaptive.skewJoin.skewedPartitionFactor 곱(기본값 5)입니다.

또한 특정 조인 유형(예: LEFT OUTER JOIN)에 대해 기울이기 처리 지원이 제한되며 왼쪽의 기울이기만 최적화할 수 있습니다.

유산

"적응형 실행"이라는 용어는 Spark 1.6 이후로 존재했지만 Spark 3.0의 새 AQE는 근본적으로 다릅니다. 기능 측면에서 Spark 1.6은 "동적으로 파티션 병합" 부분만 수행합니다. 기술 아키텍처 측면에서 새 AQE는 런타임 통계를 기반으로 쿼리를 동적으로 계획하고 다시 계획하는 프레임워크로, 이 문서에서 설명한 것과 같은 다양한 최적화를 지원하고 더 많은 잠재적 최적화를 사용하도록 확장할 수 있습니다.