You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@spark.apache.org by Ofir Manor <om...@speedata.io> on 2024/08/21 07:30:07 UTC
Re: [External] Bucketing performance question
Try using spark.sql.legacy.bucketedTableScan.outputOrdering = true , which is supposed to tell Spark to assume buckets are pre-sorted
shuffle - Spark Sort Operation in Join Despite Pre-sorted Bucketed Tables - Stack Overflow<https://stackoverflow.com/questions/78442540/spark-sort-operation-in-join-despite-pre-sorted-bucketed-tables>
Ofir
________________________________
From: Daniel Vol <dv...@undertone.com>
Sent: Tuesday, August 20, 2024 10:25 PM
To: user@spark.apache.org <us...@spark.apache.org>
Cc: aronovich.daniel@gmail.com <ar...@gmail.com>
Subject: [External] Bucketing performance question
Hello,
We have a great scenario for using bucketing (at least as per definition) :
Few data tables built hourly and partitioned by date + hour
Several processes that join those tables by ID field many times
One table is pretty big (~100G hourly), others are relatively small (but not small enough for broadcast), all joins are LEFT into the big table.
To test bucketing I took one day of data (~4.5TB in a big table) and only two tables - one big and one small, left join between and count as an action.
As a result on a cluster of 10 i4g.4xl (160 cores, 1T mem + ssd disks):
- non bucketed tables ~ 3 min to perform count
- bucketed to 160 + sort / sortWithinPartition ~ 5 min to perform count (huge mem + disk spill)
- bucketed to 16000 + sort ~ 4 min to perform count (no spill at all)
this is the data from spark ui:
non bucketed:
[image.png]
[image.png]
So we can see it reads 31525 files and 470G data (out of 4.5T total file size), uses shuffle (1000 partitions) and finishes in 3.1 min
Bucketed (to 16K buckets):
SortMerge JOIN:
[image.png]
[image.png]
Here we see it reads 16000 files and 245G of data (out of 4.5T total file size) NO shuffle, BUT SORT instead
Using hint for SHUFFLE_HASH Join improves a bit but still bad
t1.join(t2.hint("SHUFFLE_HASH"), col("id1") === col("id2"), "left).count
[image.png]
[image.png]
The code to create data:
df1
.withColumn("id1", ...)
.repartition(16000, col("id1"))
.write
.sortBy("id1") // tried with sortWithinPartition instead - faster write, same read
.bucketBy(16000, "id1")
.partitionBy("dt", "hr")
.format("parquet").mode("overwrite")
.option("path", "...")
.saveAsTable("table_1_16000")
df2
.withColumn("id2", ...)
.repartition(16000, col("id2"))
.write
.sortBy("id2")
.bucketBy(16000, "id2")
.partitionBy("dt", "hr")
.format("parquet").mode("overwrite")
.option("path", "...")
.saveAsTable("table_2_16000")
To test join (in Zeppelin):
val t1 = spark.sql("select * from table_1_16000 where dt = '...' ")
val t2 = spark.sql("select * from table_2_16000 where dt = '...' ")
t1.join(t2, col("id1") === col("id2"), "left).count
So it looks like bucketing doesn't use parquet metadata to check if data is already sorted on read - seriously affecting performance.
Just to mention - I tried to run it with 160 buckets (instead of 16000) and though each task reads only 1.4G of data => ~23G per instance (each instance has has 120G of memory + 3.5T dedicated ssd disk), I get a huge spill for both mem + disk - per my assumption due to heavy (likely unnecessary) sort:
[image.png]
Few questions:
- is Spark supposed to use sort information from a parquet file?
- if it is - should there be any difference in read after using sort or sortWithinPartition?
- is there a way somehow to force it to use sort metadata or skip sort during execution?
It is very odd that full shuffling performs much (25%) faster than bucketing.
Especially when with bucketing it reads half amount of files (16K instead of 35K) and much less total input data (270G instead of 470G)
Thanks!
Daniel