Data Transformation and Modeling · Topic 2 of 3
Joins, Deduplication, Aggregation and Spark Tuning
Databricks DEA joins and unions, broadcast joins, dropDuplicates, count, approx_count_distinct, mean and summary, plus the basic Spark tuning settings.
- 5 min
- Inner is the default join; left keeps every left row; cross has no key.
- Join on a list of names for multiple keys and one copy of each key column.
- SQL UNION removes duplicates; UNION ALL and PySpark
unionkeep them.
What it is
Silver tables are combined and summarized to answer business questions. Joins match rows across DataFrames by key, unions stack DataFrames with the same columns, deduplication removes repeated records and aggregations compute counts and averages.
Joins and aggregations shuffle data across the cluster, so a few Spark settings control how fast they run. The exam expects you to know what each setting changes and to re-measure after changing it.
How it works
Join types
| Join | Keeps |
|---|---|
| Inner (default) | Only rows with a match on both sides |
| Left (left outer) | All left rows; right columns are null where no match |
| Cross | Every left row paired with every right row; no key |
| Broadcast | Same result as the join type used; the small side is copied to every executor |
from pyspark.sql import functions as F
result = (orders
.join(customers, ["customer_id", "region"], "left")
.join(F.broadcast(countries), "country_code"))
pairs = sizes.crossJoin(colors)
Passing a list of column names joins on multiple keys and keeps one copy of each key column. A condition such as orders.id == customers.id keeps both columns, which then need dropping or renaming. In SQL, /*+ BROADCAST(c) */ is the broadcast hint.
A broadcast join avoids shuffling the large table. It fits when one side is small enough to fit in executor memory, such as a lookup table.
Union and union all
| Operation | Duplicates | Matches columns by |
|---|---|---|
SQL UNION | Removed | Position |
SQL UNION ALL | Kept | Position |
PySpark union / unionAll | Kept | Position |
PySpark unionByName | Kept | Name |
PySpark union behaves like SQL UNION ALL. Add .distinct() to remove duplicates, and use unionByName when the column order differs between the DataFrames.
Deduplication
distinct() removes rows that are identical in every column. dropDuplicates(["order_id"]) keeps one row per key and ignores the other columns; which row survives is not guaranteed.
To keep a specific row, such as the latest version, rank rows in a window and keep the first:
from pyspark.sql import Window, functions as F
w = Window.partitionBy("order_id").orderBy(F.col("updated_at").desc())
latest = (orders.withColumn("rn", F.row_number().over(w))
.filter("rn = 1").drop("rn"))
Aggregations
from pyspark.sql import functions as F
stats = orders.groupBy("region").agg(
F.count("*").alias("orders"),
F.approx_count_distinct("customer_id").alias("customers"),
F.mean("amount").alias("avg_amount"))
| Function | What it returns |
|---|---|
count("*") | All rows, including nulls |
count("col") | Rows where col is not null |
countDistinct("col") | Exact distinct count; costly on large data |
approx_count_distinct("col") | Estimated distinct count, faster; default maximum relative standard deviation 0.05 |
mean / avg | Average of non null values |
summary() | count, mean, stddev, min, quartiles and max per column |
describe() gives count, mean, stddev, min and max; summary() adds the 25%, 50% and 75% percentiles. In SQL the function is also approx_count_distinct.
Basic tuning parameters
| Setting | What it controls | When to change it |
|---|---|---|
spark.sql.shuffle.partitions | Partitions after a DataFrame or SQL shuffle (joins, groupBy); open source default 200 | Fewer for small data, more for very large shuffles |
spark.default.parallelism | Default partitions for RDD operations | Rarely for DataFrame code; it does not set DataFrame shuffle partitions |
spark.executor.memory / spark.driver.memory | Memory per executor and for the driver | Executor out of memory or spilling; driver failing on collect |
spark.sql.autoBroadcastJoinThreshold | Maximum table size broadcast automatically; default 10 MB, -1 disables | Raise for a slightly larger lookup table |
Session settings such as shuffle partitions change at runtime with spark.conf.set. Memory settings are fixed when the cluster starts, so they go in the cluster's Spark config. Serverless compute allows only a few properties, including spark.sql.shuffle.partitions, and manages memory itself.
spark.conf.set("spark.sql.shuffle.partitions", "64")
spark.conf.set("spark.sql.autoBroadcastJoinThreshold", 50 * 1024 * 1024)
Adaptive query execution, on by default, can coalesce shuffle partitions and switch to a broadcast join at runtime. Change one setting at a time and re-measure with the same data, comparing duration and stage metrics in the Spark UI.
How the exam asks about this
- "Join a 2 TB fact table to a 5 MB country lookup without shuffling the fact table." Use a broadcast join.
- "Stack two monthly DataFrames and keep every row, columns in a different order." Use unionByName.
- "Count unique visitors on billions of rows, where an estimate is acceptable and speed matters." Use approx_count_distinct.
What to remember for the exam
- Inner is the default join; left keeps every left row; cross has no key.
- Join on a list of names for multiple keys and one copy of each key column.
- SQL UNION removes duplicates; UNION ALL and PySpark
unionkeep them. dropDuplicates(subset)keeps one arbitrary row per key; userow_numberover a window to choose the row.count("col")skips nulls;approx_count_distincttrades exactness for speed.spark.sql.shuffle.partitionssets DataFrame shuffle partitions; memory settings need a cluster restart.
spark.default.parallelism applies to RDDs. Changing it does not change the number of partitions after a DataFrame join or groupBy; that is spark.sql.shuffle.partitions.
Common mistakes
Expecting PySpark union to remove duplicates. It keeps them like UNION ALL and matches by position, so swapped columns silently mix values.
Broadcasting a large table. A broadcast copies the table to every executor; a large one causes out of memory errors instead of speed.
Setting executor memory from a notebook. spark.executor.memory is read when executors start. Set it in the cluster configuration and restart.
Check yourself
Which PySpark method stacks two DataFrames whose columns are in a different order?
unionByName.unionandunionAllmatch columns by position and keep duplicates.How do you keep only the most recent row for each order_id?
Rank rows with
row_number()over a window partitioned by order_id and ordered by update time descending, then keep row 1.dropDuplicatesdoes not guarantee which row survives.Which setting changes the number of partitions after a DataFrame groupBy?
spark.sql.shuffle.partitions. It applies to joins and aggregations in DataFrame and SQL code.
Topic 2 of 3 in Data Transformation and Modeling
Test yourself on Data Transformation and Modeling
The full Databricks Data Engineer Associate question bank has 598 questions, with timed practice exams and an explanation for every answer.
This study guide is independent and is not affiliated with, endorsed by, or sponsored by Databricks. Vendor names, certification names and exam codes are trademarks of their respective owners and are used for identification only.