mixermt opened a new issue, #6056:
URL: https://github.com/apache/datafusion-comet/issues/6056

   ### What is the problem the feature request solves?
   
   When joining a large native dataset (e.g., Parquet or Iceberg) with a small 
row-based dimension table (such as a MySQL / PostgreSQL JDBC table, or any 
Spark plan containing non-native expressions/UDFs), Comet refuses to convert 
`BroadcastExchangeExec` to `CometBroadcastExchangeExec`.
   
   #### Root Cause in Code
   In `CometExecRule.scala` (lines 467-468):
   ```scala
   case b: BroadcastExchangeExec if 
b.children.forall(_.isInstanceOf[CometNativeExec]) =>
     convertToComet(b, CometBroadcastExchangeExec).getOrElse(b)
   ```
   Because JDBC is a Spark row-based source (`RowDataSourceScanExec`), 
`b.children.forall(_.isInstanceOf[CometNativeExec])` evaluates to `false`.
   
   Furthermore, `CometBroadcastExchangeExec.scala` (lines 112-116) assumes 
columnar execution:
   ```scala
   private def getByteArrayRdd(plan: SparkPlan): RDD[(Long, ChunkedByteBuffer)] 
= {
     plan.executeColumnar().mapPartitionsInternal { iter =>
       Utils.serializeBatches(iter)
     }
   }
   ```
   
   #### Fallback Cascade
   1. The build side remains a Spark `BroadcastExchangeExec` (producing 
row-based `HashedRelation`).
   2. `BroadcastHashJoinExec` cannot convert to `CometBroadcastHashJoinExec` 
because it requires native broadcast input.
   3. Comet is forced to insert `CometColumnarToRow` on the probe stream to 
feed the Spark JVM join.
   4. All downstream operations (such as `HashAggregateExec`) also fall back to 
Spark JVM.
   5. In production pipelines with large probe datasets, this JVM fallback 
causes severe GC overhead and degrades performance significantly (e.g., turning 
an aggregation that should take minutes into hours of JVM task execution).
   
   *(Note: While #6008 discusses unsupported Text scan leaves, this issue 
addresses the broader pattern of row-based data sources like JDBC and Spark 
subtrees feeding broadcast joins).*
   
   ### Describe the potential solution
   
   Support adapting row-based broadcast build sides to Arrow format so 
`CometBroadcastHashJoinExec` can remain native.
   
   Instead of requiring every leaf and intermediate operator on the build side 
to be `CometNativeExec`, provide a row-to-Arrow bridge at the 
`BroadcastExchange` boundary:
   
   1. **Driver-Side / Exchange-Level Row-to-Arrow Conversion:**
      In `CometExecRule.scala`, allow `BroadcastExchangeExec` with row-based 
children to convert to `CometBroadcastExchangeExec` when the downstream join is 
a candidate for `CometBroadcastHashJoinExec`.
   2. In `CometBroadcastExchangeExec`, if `child` is not columnar 
(`!child.supportsColumnar`), consume its rows via `child.execute()` and convert 
them to Arrow RecordBatches before broadcast (e.g., using Spark's 
`ArrowConverters` or bridging via `CometSparkToColumnarExec`).
   3. Since broadcast tables are bounded by 
`spark.sql.autoBroadcastJoinThreshold` (default 10MB), the CPU and memory cost 
of converting a few megabytes of rows to Arrow is trivial, while the benefit of 
keeping the multi-gigabyte/terabyte probe stream and downstream 
joins/aggregates in native code is enormous.
   
   ### Additional context
   
   **Reproducer scenario:**
   ```scala
   // Native large Iceberg / Parquet fact table
   val fact = spark.read.table("large_iceberg_events") 
   
   // Small dimension table from MySQL via JDBC
   val dim = spark.read.format("jdbc")
     .option("url", "jdbc:mysql://...")
     .option("dbtable", "dim_countries")
     .load()
   
   // Broadcast join
   val result = fact.join(broadcast(dim), "country_id")
     .groupBy("country_name")
     .count()
   ```
   *Current behavior:* `BroadcastExchangeExec`, `BroadcastHashJoinExec`, and 
`HashAggregateExec` all fall back to JVM.
   *Expected behavior:* `dim` is converted to Arrow at the broadcast exchange, 
allowing `CometBroadcastExchangeExec`, `CometBroadcastHashJoinExec`, and 
`CometHashAggregateExec` to execute natively.
   


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