This is an automated email from the ASF dual-hosted git repository.

JingsongLi pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/paimon.git


The following commit(s) were added to refs/heads/master by this push:
     new 2e3b41cf26 [spark] Clamp Format Table ANALYZE parallelism (#9482)
2e3b41cf26 is described below

commit 2e3b41cf26075414ae8779b4293a63c6a70e8f5d
Author: Dapeng Sun(孙大鹏) <[email protected]>
AuthorDate: Mon Aug 31 12:05:35 2026 +0800

    [spark] Clamp Format Table ANALYZE parallelism (#9482)
---
 ...PaimonAnalyzeFormatTablePartitionsCommand.scala |  5 ++--
 .../sql/CatalogManagedPartitionAnalyzeTest.scala   | 34 ++++++++++++++++++++++
 2 files changed, 37 insertions(+), 2 deletions(-)

diff --git 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/commands/PaimonAnalyzeFormatTablePartitionsCommand.scala
 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/commands/PaimonAnalyzeFormatTablePartitionsCommand.scala
index 06aee2ffa3..0f68c63773 100644
--- 
a/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/commands/PaimonAnalyzeFormatTablePartitionsCommand.scala
+++ 
b/paimon-spark/paimon-spark-common/src/main/scala/org/apache/paimon/spark/commands/PaimonAnalyzeFormatTablePartitionsCommand.scala
@@ -105,8 +105,9 @@ case class PaimonAnalyzeFormatTablePartitionsCommand(
       sparkSession: SparkSession,
       partitions: List[JMap[String, String]],
       parallelism: Int): JList[PartitionStatistics] = {
-    val tasks = math.min(parallelism, partitions.size)
-    val perTask = math.max(1, parallelism / tasks)
+    val effectiveParallelism = math.max(1, parallelism)
+    val tasks = math.min(effectiveParallelism, partitions.size)
+    val perTask = math.max(1, effectiveParallelism / tasks)
     // The table, not this command: a Spark table cannot be shipped to an 
executor.
     val table = v2Table.table
     val measured = sparkSession.sparkContext
diff --git 
a/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/CatalogManagedPartitionAnalyzeTest.scala
 
b/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/CatalogManagedPartitionAnalyzeTest.scala
index e2e85ae64e..3b2a2d1b9a 100644
--- 
a/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/CatalogManagedPartitionAnalyzeTest.scala
+++ 
b/paimon-spark/paimon-spark-ut/src/test/scala/org/apache/paimon/spark/sql/CatalogManagedPartitionAnalyzeTest.scala
@@ -338,6 +338,40 @@ class CatalogManagedPartitionAnalyzeTest extends 
PaimonSparkTestWithRestCatalogB
     }
   }
 
+  test("a full ANALYZE clamps non-positive statistics parallelism") {
+    Seq("zero" -> 0, "negative" -> -1).foreach {
+      case (label, parallelism) =>
+        val tableName = s"analyze_${label}_parallelism"
+        withTable(tableName) {
+          sql(s"""CREATE TABLE $tableName (id INT, payload STRING, dt STRING, 
hour STRING)
+                 |USING PARQUET
+                 |PARTITIONED BY (dt, hour)
+                 |TBLPROPERTIES (
+                 |  'format-table.implementation' = 'paimon',
+                 |  'metastore.partitioned-table' = 'true')
+                 |""".stripMargin)
+          sql(s"""INSERT INTO ${qualified(tableName)}
+                 |VALUES (1, 'a', '20260101', '00'), (2, 'b', '20260101', '00')
+                 |""".stripMargin)
+          copyPartitionFiles(tableName, "20260101", "20260102")
+          repair(tableName)
+          assert(
+            !PartitionStatistics.isKnown(statisticsOf(tableName, "20260102", 
"00").recordCount()))
+
+          withSparkSQLConf(
+            "spark.paimon.format-table.statistics.parallelism" -> 
parallelism.toString) {
+            sql(
+              s"ANALYZE TABLE ${qualified(tableName)} PARTITION (dt = 
'20260102') " +
+                s"COMPUTE STATISTICS").collect()
+          }
+
+          val scanned = statisticsOf(tableName, "20260102", "00")
+          // The exact row count confirms that ANALYZE completed the Parquet 
footer scan.
+          assert(scanned.recordCount() == 2L, scanned.toString)
+        }
+    }
+  }
+
   test("catalog partition row counts feed scan statistics after partition 
pruning") {
     val tableName = "analyze_scan_statistics"
     withTable(tableName) {

Reply via email to