From e33826582d27a50d94187db8af1ab03e96194b80 Mon Sep 17 00:00:00 2001 From: 924060929 Date: Fri, 17 Jul 2026 17:01:14 +0800 Subject: [PATCH] [fix](nereids) stabilize the flaky shuffle_left_join regression test With the nereids distribute planner on, the join in this suite can be planned either as a partitioned shuffle or as a left-to-right bucket shuffle (the left aggregated side shuffled onto the right table's storage buckets), and the two candidates are chosen by cost. That cost depends on two things that are not stable during the test: - the scan row count, which is reported asynchronously after the insert, so an unreported count clamps to 1 and yields a partitioned shuffle, while the real count yields a bucket shuffle; - the bucket-shuffle downgrade gate, which turns bucket shuffle back into a partitioned shuffle when the bucket count is small relative to the instance count, so the plan also depends on the number of backends. As a result the asserted plan flipped between INNER JOIN(PARTITIONED) and INNER JOIN(BUCKET_SHUFFLE) depending on timing and cluster topology. The suite is meant to assert the left-to-right bucket shuffle, which saves one exchange versus a plain partitioned shuffle. Restore that assertion and make it deterministic: - analyze the table with sync so the row count is fixed instead of racing the async tablet report; - set bucket_shuffle_downgrade_ratio=0 so the plan does not depend on the number of backends. --- .../distribute/shuffle_left_join.groovy | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/regression-test/suites/nereids_syntax_p0/distribute/shuffle_left_join.groovy b/regression-test/suites/nereids_syntax_p0/distribute/shuffle_left_join.groovy index 4ee14eba4817f1..356bf9e5fd401c 100644 --- a/regression-test/suites/nereids_syntax_p0/distribute/shuffle_left_join.groovy +++ b/regression-test/suites/nereids_syntax_p0/distribute/shuffle_left_join.groovy @@ -18,6 +18,17 @@ import java.util.stream.Collectors // under the License. suite("shuffle_left_join") { + // The point of this suite is the left-to-right bucket shuffle: with the nereids distribute + // planner on, the aggregated left side is shuffled onto the right table's storage buckets, so + // the join becomes a bucket shuffle join that saves one exchange versus a plain partitioned + // shuffle. The planner chooses between the two candidates by cost, which depends on the scan + // row count and on the bucket-shuffle downgrade gate. Both are pinned below so the asserted + // plan is stable: + // - `analyze ... with sync` fixes the row count (otherwise it is reported asynchronously + // after the insert, and the plan flips depending on whether the report has landed yet); + // - `bucket_shuffle_downgrade_ratio=0` disables the downgrade that turns bucket shuffle back + // into a partitioned shuffle when the bucket count is small relative to the instance count, + // which otherwise makes the plan depend on the number of backends. multi_sql """ drop table if exists test_shuffle_left; @@ -35,11 +46,14 @@ suite("shuffle_left_join") { sync; + analyze table test_shuffle_left with sync; + set enable_nereids_distribute_planner=false; set enable_pipeline_x_engine=true; set disable_join_reorder=true; set enable_local_shuffle=false; set force_to_local_shuffle=false; + set bucket_shuffle_downgrade_ratio=0; """ def extractFragment = { String sqlStr, String containsString, Closure checkExchangeNum -> @@ -95,8 +109,8 @@ suite("shuffle_left_join") { .collect(Collectors.joining("\n")) logger.info("Variables:\n${variableString}") - extractFragment(sqlStr, "INNER JOIN(PARTITIONED)") { exchangeNum -> - assertTrue(exchangeNum == 2) + extractFragment(sqlStr, "INNER JOIN(BUCKET_SHUFFLE)") { exchangeNum -> + assertTrue(exchangeNum == 1) } explain {