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


##########
sql/catalyst/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala:
##########
@@ -8050,7 +8051,11 @@ object SQLConf {
         "common join to be merged into a single scan. A filter attribute is 
only propagated " +
         "through a join when it originates from the non-nullable (preserved) 
side: the left side " +
         "of LeftOuter/LeftSemi/LeftAnti, the right side of RightOuter, or 
either side of " +
-        "Inner/Cross. FullOuter joins are never eligible. " +
+        "Inner/Cross. FullOuter joins are never eligible. When the two 
subplans filter " +

Review Comment:
   The symmetric and through-join docs, the tuning guide rows, the class doc 
and the new migration guide entry now state the rule. One subplan filters a 
join child with a condition that the other doesn't share, and the other subplan 
does so on the other join child. The two shapes are examples now 
([0fb8bcce413](https://github.com/apache/spark/pull/59321/commits/0fb8bcce413b83ac6c4ab82e9a8e30e513f2d271)).
   



##########
sql/core/src/main/scala/org/apache/spark/sql/execution/planmerging/PlanMerger.scala:
##########
@@ -717,7 +750,8 @@ class PlanMerger(
                       mergedJoin
                     }
                     Some(TryMergeResult(mergedPlan, npMapping, npFilter, 
cpFilter,
-                      dsv2Merged = leftDsv2Merged || rightDsv2Merged))
+                      dsv2Merged = leftDsv2Merged || rightDsv2Merged,
+                      cachedSideFiltered = leftCPSideFiltered || 
rightCPSideFiltered))

Review Comment:
   Added "SPARK-60106: Do not merge subqueries that filter different children 
of nested joins". It expects no merge with symmetric off and a merge with it 
on. It fails if the Join arm stops forwarding `cachedSideFiltered` 
([0fb8bcce413](https://github.com/apache/spark/pull/59321/commits/0fb8bcce413b83ac6c4ab82e9a8e30e513f2d271)).
   



##########
sql/core/src/main/scala/org/apache/spark/sql/execution/planmerging/PlanMerger.scala:
##########
@@ -513,8 +536,8 @@ class PlanMerger(
                 tryBuildFilterDSv2ScanChild(mergedChild, deferred, 
Some(cp.condition))
                   .map { prunedChild =>
                     val mergedPlan = Filter(cp.condition, prunedChild)
-                    TryMergeResult(
-                      mergedPlan, npMapping, npFilter, cpFilter, dsv2Merged = 
dsv2Merged)
+                    TryMergeResult(mergedPlan, npMapping, npFilter, cpFilter,
+                      dsv2Merged = dsv2Merged, cachedSideFiltered = 
cpSideFiltered)

Review Comment:
   Added "SPARK-60106: Merge subqueries that share a filter on one join child". 
Your example doesn't reach this line, because identical subtrees are reused 
before the Filter arms run. So in the test both subqueries filter `a > 1` above 
different projections. It fails if this line reports `true` 
([0fb8bcce413](https://github.com/apache/spark/pull/59321/commits/0fb8bcce413b83ac6c4ab82e9a8e30e513f2d271)).
   



##########
sql/core/src/main/scala/org/apache/spark/sql/execution/planmerging/PlanMerger.scala:
##########
@@ -319,14 +325,26 @@ class PlanMerger(
    *                   pair that is NOT the innermost one still recognize the 
merge below it and
    *                   apply the DSv2-symmetric exemption. It only ever gates 
behaviour when
    *                   `dsv2SymmetricFilterPropagationEnabled` is on.
+   * @param cachedSideFiltered Whether every plan merged into the cached plan 
filters this subtree
+   *                           with a filter that the new plan doesn't share. 
It is set whenever
+   *                           `cachedPlanFilter` is. It is also set when a 
merged Filter from an
+   *                           earlier round filters the subtree, unless the 
new plan reuses one of
+   *                           its sides. That Filter's condition is not in
+   *                           `cachedPlanFilter`, because the cached 
aggregates already carry it.
+   *                           The fact goes up to the nearest Aggregate, 
which consumes the filters
+   *                           below it, so a Join arm can tell which of its 
children the cached
+   *                           plans filter. The merged Filter case only 
matters without
+   *                           `symmetricFilterPropagationEnabled`, where such 
a Filter can only
+   *                           come from the DSv2-symmetric exemption.
    */
   case class TryMergeResult(
       mergedPlan: LogicalPlan,
       newPlanMapping: AttributeMap[Attribute],
       newPlanFilter: Option[Attribute] = None,
       cachedPlanFilter: Option[Attribute] = None,
       dsv2DeferredScan: Option[DSv2DeferredScan] = None,
-      dsv2Merged: Boolean = false)
+      dsv2Merged: Boolean = false,
+      cachedSideFiltered: Boolean = false)

Review Comment:
   Dropped the default. The identical result, the two Aggregate results and the 
two DSv2 leaf results now pass `false` explicitly 
([0fb8bcce413](https://github.com/apache/spark/pull/59321/commits/0fb8bcce413b83ac6c4ab82e9a8e30e513f2d271)).
   



##########
sql/catalyst/src/main/scala/org/apache/spark/sql/internal/SQLConf.scala:
##########
@@ -8050,7 +8051,11 @@ object SQLConf {
         "common join to be merged into a single scan. A filter attribute is 
only propagated " +
         "through a join when it originates from the non-nullable (preserved) 
side: the left side " +
         "of LeftOuter/LeftSemi/LeftAnti, the right side of RightOuter, or 
either side of " +
-        "Inner/Cross. FullOuter joins are never eligible. " +
+        "Inner/Cross. FullOuter joins are never eligible. When the two 
subplans filter " +
+        "different children of the join, the merge also needs " +

Review Comment:
   Added an entry to the 4.3 to 4.4 section. It names the symmetric config and 
says that it also enables the other symmetric merges. Since this is a plan 
change under a non-default config, it goes to master and branch-4.x only. I 
changed the JIRA to an Improvement and won't backport it to 4.3 or 4.2 
([0fb8bcce413](https://github.com/apache/spark/pull/59321/commits/0fb8bcce413b83ac6c4ab82e9a8e30e513f2d271)).
   



##########
docs/sql-performance-tuning.md:
##########
@@ -354,7 +354,7 @@ SELECT
   (SELECT avg(ss_net_paid) FROM store_sales WHERE ss_quantity BETWEEN 21 AND 
40)
 ```
 
-In TPC-DS benchmark runs, enabling symmetric filter propagation made `q9` and 
`q28` about 3.5x faster, and enabling it together with propagation through 
joins made `q88` about 7x and `q90` about 2x faster. See 
[SPARK-40193](https://issues.apache.org/jira/browse/SPARK-40193) and 
[SPARK-56677](https://issues.apache.org/jira/browse/SPARK-56677) for these 
measurements. The trade-off depends on the tables: the gain is largest when the 
differing filters are on columns the data source cannot prune on, and the risk 
is highest on heavily partitioned or file-pruned tables where the widened 
filter loses that pruning. Validate it on your own workload before enabling it 
in production.
+In TPC-DS benchmark runs, enabling symmetric filter propagation made `q9` and 
`q28` about 3.5x faster, and enabling it together with propagation through 
joins made `q88` about 7x and `q90` about 2x faster. See 
[SPARK-40193](https://issues.apache.org/jira/browse/SPARK-40193) and 
[SPARK-56677](https://issues.apache.org/jira/browse/SPARK-56677) for these 
measurements. The trade-off depends on the tables: the gain is largest when the 
differing filters are on columns the data source cannot prune on, and the risk 
is highest on heavily partitioned or file-pruned tables where the widened 
filter loses that pruning. With propagation through joins, two subplans that 
filter different join children also merge, and so do two that filter both join 
children with different conditions. The merged join then builds join pairs that 
neither subplan needs, which can multiply its work. Validate it on your own 
workload before enabling it in production.

Review Comment:
   Done. The sentence now starts with "With both configurations on" and states 
the rule 
([0fb8bcce413](https://github.com/apache/spark/pull/59321/commits/0fb8bcce413b83ac6c4ab82e9a8e30e513f2d271)).
   



-- 
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