peter-toth commented on code in PR #57762:
URL: https://github.com/apache/spark/pull/57762#discussion_r3713962570


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala:
##########
@@ -1105,7 +1105,9 @@ object SQLConf {
       .doc("When true, the planner requires all the clustering keys as the 
hash partition keys " +
         "of the children, to eliminate the shuffles for the operator that 
needs its children to " +
         "be co-partitioned, such as JOIN node. This is to avoid data skews 
which can lead to " +
-        "significant performance regression if shuffles are eliminated.")
+        "significant performance regression if shuffles are eliminated. For V2 
data source " +
+        "partitioning (storage-partitioned join), the check ignores key order 
and duplicated " +
+        "clustering keys: it requires every clustering key to be covered by 
the partition keys.")

Review Comment:
   **Finding 6.** (Replaces my earlier finding-7 comment on this line — that 
one is withdrawn, see the review body.)
   
   "the check ignores key order and duplicated clustering keys" names two 
relaxations that no query reaches:
   
   - **Key order** was already handled before this gate ran: 
`reorderJoinPredicates` runs first in the same `transformUp` case, and 
`reorderJoinKeysRecursively` has explicit `KeyedPartitioning` cases that 
permute the join keys into partition-key order 
(`EnsureRequirements.scala:412-426`). In the one situation it can't fix — the 
two sides' partition orders disagreeing relative to the join pairing — 
`areKeysCompatible` rejects the pair anyway, gate or no gate.
   - **Duplicated clustering keys** don't survive the optimizer: 
`BooleanSimplification` splits the whole conjunction and dedups it through an 
`ExpressionSet` (`expressions.scala:458-493`, its own comment being `(a && b) 
&& a && (a && c) => a && b && c`), so `ON t1.a = t2.a AND t1.b = t2.c AND t1.b 
= t2.c` collapses to two key pairs before `ExtractEquiJoinKeys` sees it. An 
*asymmetric* duplicate does survive the optimizer but dies in the planner: 
coverage is applied per side, so `ON t1.a = t2.a AND t1.b = t2.b AND t1.b = 
t2.c` needs `c` covered on t2, and `areKeysCompatible` then rejects 2 vs 3 
partition expressions (`partitioning.scala:1304`).
   
   What the check does relax is the *partition* side: a partitioning may now 
have more expressions than the join has key positions. Both sides `PARTITIONED 
BY (bucket(8, id), truncate(4, id))` joined `ON t1.id = t2.id` gives cluster 
keys `[id]` against partition attrs `[id, id]` — the old `attributes.length == 
clustering.length` failed, coverage passes, and it is safe because the 
partition tuple is still a function of the join key. That, plus the 
`allowKeysSubsetOfPartitionKeys` direction, is the whole win.
   
   One framing note while you're rewriting it. This is a pure relaxation of the 
config-`true` path, so nothing it enables was previously impossible — all of it 
was reachable by setting `requireAllClusterKeysForCoPartition=false`. What it 
buys is that you no longer have to switch that guard off globally, which would 
also admit the genuinely risky partition-keys-cover-part-of-the-join-keys case, 
to get two shapes that carry no skew risk: join keys a subset of the partition 
columns, and a join-key column partitioned by more than one transform. That 
reads as a stronger motivation than the duplicated-join-key story, and it is 
what the tests actually demonstrate.
   
   The current wording also appears in `docs/sql-migration-guide.md:27` 
("duplicated join keys no longer prevent shuffle elimination"), 
`docs/sql-performance-tuning.md:538` ("ignoring key order and duplicated keys") 
and case 1 of the PR description, so all four want the same correction. For 
this one (as a plain block, since the anchor can't reach line 1109):
   
   ```scala
         .doc("When true, the planner requires all the clustering keys as the 
hash partition keys " +
           "of the children, to eliminate the shuffles for the operator that 
needs its children to " +
           "be co-partitioned, such as JOIN node. This is to avoid data skews 
which can lead to " +
           "significant performance regression if shuffles are eliminated. For 
V2 data source " +
           "partitioning (storage-partitioned join), every clustering key must 
be covered by some " +
           "partition key, rather than matching the partition keys 
positionally, so a column " +
           "partitioned by more than one transform does not prevent shuffle 
elimination.")
   ```
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to