Aurora DSQL EXPLAIN 계획의 일괄 중첩 루프 조인
쿼리가 Aurora DSQL이 스토리지에서 효율적으로 스캔할 수 있는 내부 입력에 작은 외부 입력을 조인하면 Aurora DSQL은 Nested Loop (Batched Join) 계획을 선택할 수 있습니다. 이 조인 유형은 내부를 탐색하기 전에 여러 외부 행을 그룹화하여 컴퓨팅 계층과 스토리지 계층 간의 왕복을 줄입니다.
표준 중첩 루프는 한 번에 하나의 외부 행을 처리하고 모든 행에 대해 내부 스캔을 다시 실행합니다. 일괄 중첩 루프 조인은 외부 행의 배치를 수집하고 전체 배치에 대한 내부 스캔 작업을 빌드한 다음 반환된 내부 행을 일치하는 외부 행에 다시 조인합니다.
일괄 중첩 루프 조인의 작동 방식
-
Aurora DSQL은 조인의 외부에서 행 배치를 읽습니다.
-
내부 측이 외부 측에
Index Cond파라미터가 지정된Index Scan또는Index Only Scan인 경우 Aurora DSQL은 각 외부 행의 조건을 바인딩하고 결과 인덱스 스캔 키를 하나의 일괄 내부 스캔으로 결합합니다. 다른 조인 조건자는 내부 스캔을 구동하지 않습니다. -
외부 파라미터가 지정된
Index Cond없는Index Scan또는Index Only Scan은Full Scan또는Sequential Scan처럼 동작합니다. Aurora DSQL에는 결합할 파라미터화된 인덱스 스캔 키가 없으며 외부 행당 하나의 내부 스캔 대신 외부 배치당 하나의 내부 스캔을 실행합니다. -
Aurora DSQL은 배치를 위해 내부 측의 행이 도착하는 대로 이를 스트리밍합니다. 조인하기 전에 배치에 대한 전체 내부 결과를 구체화하지는 않습니다.
-
내부
Index Scan또는Index Only Scan에 외부 파라미터가 지정된Index Cond가 있는 경우 Aurora DSQL은Recheck Cond를 사용하여 반환된 각 내부 행을 배치의 해당 외부 행과 다시 일치시킵니다. 그런 다음 Aurora DSQL은 나머지 조인 조건자를 적용합니다. 외부 파라미터화된Index Cond가 없으면 Aurora DSQL은 외부 배치에 대해 스트리밍된 각 내부 행과 일치할 때 조인 조건자를 직접 적용합니다. -
왼쪽 및 안티 조인의 경우 Aurora DSQL은 일치하는 외부 행을 추적하고 배치에 대한 내부 스캔이 완료된 후 일치하지 않는 행을 내보냅니다.
이 접근 방식은 내부 측이 파라미터화된 Index Cond가 있는 인덱스 스캔인 경우에 가장 유용합니다. 결합된 스캔 키가 전체 외부 배치에 대한 대상 스토리지 액세스를 제공하기 때문입니다.
Aurora DSQL에서 이 조인을 사용하는 경우
Aurora DSQL은 조인의 내부가 물리적 스캔 노드 즉, Index Scan, Index Only Scan, Full
Scan, 또는 Sequential Scan이고, 외부 행마다 내부 스캔을 수행하는 것보다 일괄 처리 방식의 비용이 더 적게 들 것으로 예상되는 경우 일괄 중첩 루프 조인을 고려합니다. 실제로 가장 큰 이점은 일반적으로 더 작은 외부 입력과 외부에 Index Cond 파라미터가 지정된 내부 인덱스 스캔에서 비롯됩니다.
해시 조인 또는 병합 조인과 같이 다른 계획 형태가 더 저렴한 경우 Aurora DSQL은 대신 해당 계획을 선택합니다. 튜닝 중에 계획 형태를 비교하려면 현재 세션에 대해 일괄 중첩 루프 조인을 비활성화할 수 있습니다.
SET dsql.enable_batched_nestloop = off;
일괄 중첩 루프 조인 출력을 읽는 방법
다음 쿼리는 Aurora DSQL EXPLAIN 계획 읽기의 transaction 샘플 및 account 테이블을 사용합니다.
EXPLAIN SELECT t.account_id, a.balance FROM transaction t LEFT JOIN account a ON t.account_id = a.customer_id AND a.balance > CASE WHEN t.description LIKE 'fee%' THEN 0 ELSE 100 END WHERE t.transaction_date >= '2025-01-01' AND (a.status = 'active' OR a.customer_id IS NULL) ORDER BY t.account_id;
EXPLAIN 계획에는 다음과 유사한 출력이 포함될 수 있습니다.
Sort
Sort Key: t.account_id
-> Nested Loop (Batched Join)
Filter: (((status)::text = 'active'::text) OR (customer_id IS NULL))
Join Type: Left
Recheck Cond: (customer_id = t.account_id)
Join Filter: (balance > CASE WHEN (t.description ~~ 'fee%'::text) THEN '0'::numeric ELSE '100'::numeric END)
-> Full Scan (btree-table) on transaction t
-> Storage Scan on transaction t
Filters: (transaction_date >= '2025-01-01 00:00:00'::timestamp without time zone)
-> B-Tree Scan on transaction t
-> Index Only Scan using idx1 on account a
Index Cond: (customer_id = t.account_id)
Nested Loop (Batched Join)-
Aurora DSQL이 조인의 내부 측을 탐색하기 전에 외부 행을 일괄 처리하고 있음을 보여줍니다.
Index Cond-
현재 배치의 내부 측을 프로브하는 데 사용되는 조건자를 표시합니다. 내부 측이
Index Scan또는Index Only Scan인 경우, 이 조건자는 조인의 외부 측에서 열을 참조하는 경우가 많습니다. Filter-
조인 결과에 적용된 조건을 표시합니다. 이 예제에서는
WHERE (a.status = 'active' OR a.customer_id IS NULL)조건이 여기에 나타납니다. 표준 SQL 왼쪽 조인 의미 체계에서는 이 조건을 내부 스캔으로 푸시할 수 없습니다. 이렇게 하면 쿼리 결과가 변경되기 때문입니다. Aurora DSQL은 조인 노드에 필터로 표시합니다. 반대로t.transaction_date의 조건은 외부 테이블만 참조하므로 외부 물리적 스캔 아래에 나타납니다. Join Type-
Left,Semi또는Anti와 같이 일괄 조인의 조인 의미 체계를 표시합니다. Recheck Cond-
내부 측이
Index Scan이거나 조인의 외부 측에Index Cond파라미터가 하나 이상 있는Index Only Scan인 경우에만 나타납니다. 반환된 각 내부 행에 대해 Aurora DSQL은 배치의 모든 외부 행에 대해 재점검을 실행하여 해당 프로브를 생성한 외부 행을 결정하고 해당 내부 행과 조인해야 하는 외부 행을 결정합니다. Join Filter-
Aurora DSQL이 내부 행을 배치의 후보 외부 행과 다시 일치시킨 후 평가하는 조인 조건자를 표시합니다. 이러한 조건자는 조인하는 행 페어에 영향을 미치지만,
Index Cond가 구동하는 방식으로 스토리지 프로브를 구동하지는 않습니다. - 이전 정렬 노드
-
쿼리에 정렬된 출력이 필요할 때 나타날 수 있습니다. 배치 중첩 루프 조인은 표준 중첩 루프와 동일한 출력 순서 보장을 유지하지 않으므로 Aurora DSQL은 최종 결과 세트를 반환하기 전에 명시적 정렬을 추가할 수 있습니다.