Performance Tuning โ Partitions, Repartition, and Coalesce in PySpark
At NeoMart, large-scale pipelines often process billions of rows.
Efficient partitioning is critical to:
- Reduce shuffle and disk I/O
- Improve join and aggregation performance
- Balance task distribution across executors
This chapter explains partitions, repartition, and coalesce with practical examples.
1. Understanding Partitionsโ
- Spark divides data into partitions โ processed in parallel
- Number of partitions affects parallelism and performance
- Default partition count depends on cluster configuration and source
print(df.rdd.getNumPartitions())
- Returns the number of partitions for
df
2. Repartition โ Increase or Shuffle Partitionsโ
repartition(n)โ reshuffles data intonpartitions- Useful for parallelizing wide transformations or joins
# Repartition to 8 partitions
df_repart = df.repartition(8)
print(df_repart.rdd.getNumPartitions())
Storyโ
NeoMart joins two large datasets.
- Original partitions = 2 โ tasks underutilized
- Repartition to 8 โ tasks distributed evenly โ faster execution
3. Coalesce โ Reduce Partitions Without Shuffleโ
coalesce(n)โ reduces partitions without full shuffle- Ideal after filtering or aggregation
# Reduce partitions to 2 without shuffle
df_coalesce = df_repart.coalesce(2)
print(df_coalesce.rdd.getNumPartitions())
- Avoids expensive shuffle operation โ faster than
repartitionwhen reducing partitions
4. Practical Exampleโ
from pyspark.sql import SparkSession
from pyspark.sql import functions as F
spark = SparkSession.builder.appName("NeoMart").getOrCreate()
data = [(i, f"product_{i}", i*10) for i in range(1, 101)]
df = spark.createDataFrame(data, ["id", "name", "price"])
# Check initial partitions
print("Initial partitions:", df.rdd.getNumPartitions())
# Increase partitions for join
df_repart = df.repartition(10)
print("After repartition:", df_repart.rdd.getNumPartitions())
# Filter expensive operation
df_filtered = df_repart.filter(F.col("price") > 500)
# Reduce partitions after filtering
df_final = df_filtered.coalesce(3)
print("After coalesce:", df_final.rdd.getNumPartitions())
Outputโ
Initial partitions: 4
After repartition: 10
After coalesce: 3
- Shuffles only occur in repartition, not in coalesce
- Balanced partitions โ better task parallelism
5. Best Practicesโ
โ Repartition before wide transformations or joins โ balance tasks
โ Coalesce after filtering or aggregations โ avoid small files and shuffle
โ Avoid too many partitions โ overhead of task scheduling
โ Avoid too few partitions โ underutilized cluster resources
โ Combine with partitioning on columns for large datasets
6. Story Exampleโ
NeoMart runs nightly ETL on 500 million rows:
- Original partitions = 50 โ join tasks uneven
- Repartition to 200 โ full cluster utilization โ faster joins
- After filtering high-value products โ coalesce to 50 โ fewer small files
- Result โ 3x faster ETL runtime
Summaryโ
- Partitions โ control parallelism
- Repartition(n) โ increase partitions with shuffle
- Coalesce(n) โ decrease partitions without shuffle
- Proper tuning โ faster joins, reduced shuffle, optimized cluster utilization
NeoMart pipelines achieve high throughput and low latency by carefully repartitioning and coalescing DataFrames.
Next Topic โ Introduction to Structured Streaming.