Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Data Engineering  Module 9 – Batch processing with Apache Spark

Spark performance: AQE, skew and spills

Tell skew from spills in the row counts of a slow Spark job, see what adaptive execution fixes by itself, and decide when caching a DataFrame pays.

  • Advanced
  • 25 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7 and pyspark 4.2.0
  • By MySmartCoPilot
Free core, Pro depth: 7 of 25 minutes free
Free: Three shapes of a slow stage, and the count behind each · Skew as a number: the largest partition against the mean · Practise. With a pass: 3 in-depth parts and 3 interview answers, about 18 minutes.

What you will learn

  • Diagnose skew, spills and too many tiny tasks from per-partition row counts
  • Explain what adaptive skew-join handling splits, and when salting is needed instead
  • Decide whether a DataFrame is worth caching, and release it with unpersist
  • Size a job's shuffle partitions, cores and executor memory from its data size

Before you start

What you’ll learn · Before you start

What you will learn

  • Diagnose skew, spills and too many tiny tasks from per-partition row counts
  • Explain what adaptive skew-join handling splits, and when salting is needed instead
  • Decide whether a DataFrame is worth caching, and release it with unpersist
  • Size a job's shuffle partitions, cores and executor memory from its data size

Before you start

On this page

A Spark job slows down, and its slowest stage shows 7 of its 8 tasks finished while one is still running. That one task holds 820,000 of the stage’s 1,000,000 rows, and more cores would not take a single row off it. So when a job is slow, look first at the tasks of its slowest stage and count the rows each one holds: one task far above the rest is skew, every task too large for its memory spills, and thousands of near-empty tasks mean a stage split too finely.

The row and task counts below were printed by PySpark 4.2.0 in local mode on fixed generated data: counts you can reproduce, never durations. Some of what they show, adaptive execution repairs by itself.

Three shapes of a slow stage, and the count behind each

A stage runs one task per partition and ends with its last task; where partitions come from is covered in Spark joins, shuffles and partitions. Given the partitions, three spreads of rows explain most slow stages:

  • Skew. One key value holds far more rows than the rest, so one partition does too, and its task is the straggler: A task that runs far longer than the other tasks of its stage, so the whole stage, and every stage after it, waits for that one task to finish. the stage waits for.
  • Spills. Every task holds more than its memory takes, so its sort or hash table goes to local disk, a In Spark, a task writing part of its sort buffer or hash table to local disk because it could not get more execution memory, then reading that part back to finish its work., and is read back.
  • Too many tiny tasks. Thousands of partitions hold a few rows each, and starting a task costs more than its work.

data skew: An uneven spread of rows over the partitions of a stage, usually because one key value is far more common than the others, so the task that holds that key does most of the stage's work. is the shape more machines never fix, because one task runs on one core. Spills are quieter: the Spark UI’s stage page reports them per task as shuffle spill (memory) and shuffle spill (disk). A fourth cost shows in no task count: a DataFrame that two actions read is computed twice, unless caching keeps it.

adaptive query execution: A Spark feature, on by default, that re-plans parts of a query at runtime from the actual rows and bytes it has seen, under an AdaptiveSparkPlan root. (AQE) re-plans a query between stages from the sizes finished stages report, and AQE is on by default in Spark 4.2. Its skew handling is documented for the two joins that shuffle both sides, sort-merge and shuffled hash. The 4.2 UI shows a query’s initial and final adaptive plans side by side, where a split shows. Read a slow stage in this order:

Interactive · stage by stage Reading a slow stage from its tasks Step through the three checks in the order they are cheapest to make, with the numbers of this lesson's run.
Reading a slow stage from its tasks, step 6 of 6. Showing Open the slow stage, One task far above? (6.56 times the mean: skew), Every task spilling?, Many near-empty tasks?, Even and fitting. In focus: Even and fitting.Open the slow stagetasks and rows per taskOne task far above?6.56 times the mean: skewEvery task spilling?spill metrics above zeroMany near-empty tasks?rows per task, per coreEven and fittingthen read the query plan

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. Start from the slowest stage. A slow job is nearly always one slow stage. Its tasks are listed with the rows each one read, and those counts, not the durations, say which of three shapes the stage has.
  2. Compare the largest task. Put the largest task's rows next to the mean. In this lesson's run one partition of 8 held 820,000 of 1,000,000 rows, 6.56 times the mean of 125,000, while 7 of the 8 held less than the mean.
  3. Why cores cannot help. One task runs on one core, so the stage ends when the 820,000-row task ends. The other cores finish early and wait: that task is a straggler, and only spreading its key over more tasks shortens the stage.
  4. Every task too big. If the tasks are even but each one is large, a task's sort or hash table can outgrow its memory and spill to local disk, to be read back later. The stage page reports it as shuffle spill (memory) and shuffle spill (disk).
  5. Thousands of tiny tasks. The opposite shape is a stage of thousands of tasks holding a few rows each. Each task still has to be scheduled, started and finished, so the overhead outweighs the work it does.
  6. Then the plan. A stage whose tasks are even, fit their memory and are not tiny has the right partitions. What is left is the query itself: a shuffle it could avoid, or a step it repeats.

Only the last check needs the query itself.

Checkpoint

Check: Three shapes of a slow stage

  1. Question 1 of 2 A stage runs 8 tasks. Seven finish with about 25,000 rows each; the eighth holds 820,000 rows and is still running. Which shape does the stage have?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: Skew, because one task holds far more rows than the rest

    Compare the largest task with the others first. One task far above the rest is skew; every task too large for its memory is a spill; thousands of near-empty tasks are a stage split too finely.

  2. Question 2 of 2 For the same stage, the team doubles the cluster's cores. What happens to the task that holds 820,000 rows?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: It still runs on one core with all 820,000 rows, so the stage ends about as late as before

    Data skew is the shape more machines never fix, because one task runs on one core. The stage can only end sooner if the hot key's rows are spread over more tasks.

Skew as a number: the largest partition against the mean

A ratio says more than a list of tasks. The run below builds 1,000,000 orders over 41 cities, sends four orders in five to city 0, and spreads them over 8 partitions twice, by a hash of the order id and of the city id, counting each partition’s rows with spark_partition_id().

One million orders, one hot city, spread over 8 partitions two ways

spt_skew_session.py

"""Session driver: run skew_counts.py on PySpark 4.2.0 in local mode, inside a private lab folder.

Spark needs a Java runtime and the pyspark package. The driver points at the pinned ones (Java 21 and PySpark
4.2.0), gives Spark a home and a temporary folder inside the lab, binds it to 127.0.0.1 and prints only what the
program prints: configuration values and row counts, never Spark's own log lines or paths.
"""

import os
import pwd
import subprocess
import sys
import tempfile
from pathlib import Path

JAVA_HOME = os.path.join(pwd.getpwuid(os.getuid()).pw_dir, ".local", "share", "mise", "installs", "java",
                         "temurin-21.0.12+101.0.LTS")
HERE = Path(__file__).resolve().parent
PROGRAM = "skew_counts.py"


def pinned_pyspark():
    """The folder that holds the pinned pyspark 4.2.0 package, or None to use the one installed for this Python."""
    for folder in [Path.cwd(), *Path.cwd().parents, *HERE.parents]:
        for found in folder.glob("*/toolchains/pyspark-4.2.0/python"):
            return str(found)
    return None


with tempfile.TemporaryDirectory(prefix="spt-skew-") as lab:
    for name in ("home", "tmp", "out"):
        os.makedirs(os.path.join(lab, name))
    java_home = JAVA_HOME if os.path.isdir(JAVA_HOME) else os.environ.get("JAVA_HOME", "")
    env = {
        "PATH": os.pathsep.join([os.path.join(java_home, "bin"), "/usr/bin", "/bin"]),
        "JAVA_HOME": java_home,
        "HOME": os.path.join(lab, "home"),
        "TMPDIR": os.path.join(lab, "tmp"),
        "WORK": os.path.join(lab, "out"),
        "SPARK_LOCAL_IP": "127.0.0.1",
        "PYSPARK_PYTHON": sys.executable,
        "TZ": "UTC",
        "LANG": "en_US.UTF-8",
    }
    package = pinned_pyspark()
    if package:
        env["PYTHONPATH"] = package
    done = subprocess.run([sys.executable, str(HERE / PROGRAM)], cwd=lab, env=env,
                          capture_output=True, text=True, check=False)
    print(done.stdout.replace(lab, "<lab>").rstrip())
    if done.returncode != 0:
        last = [line for line in done.stderr.splitlines() if line.strip()][-1:] or ["no message"]
        print(PROGRAM, "stopped with exit status", done.returncode, "-", last[0].replace(lab, "<lab>"))
        sys.exit(done.returncode)

Output

PySpark 4.2.0, local mode on 2 cores
spark.sql.adaptive.enabled = true (not set by this program)
spark.sql.adaptive.skewJoin.enabled = true (not set by this program)

orders = 1000000, cities = 41
city 0 holds 800000 orders (80.0 % of all); each other city holds 5000

hashed on order_id into 8 partitions (a key with 1,000,000 values)
  rows per partition: [124954, 124686, 124925, 125210, 125164, 125249, 125087, 124725]
  largest = 125249, mean = 125000.0, largest / mean = 1.00
  the largest partition holds 12.5 % of the rows; 4 of 8 partitions hold less than the mean

hashed on city_id into 8 partitions (a key with 41 values, one of them hot)
  rows per partition: [25000, 30000, 15000, 40000, 10000, 30000, 30000, 820000]
  largest = 820000, mean = 125000.0, largest / mean = 6.56
  the largest partition holds 82.0 % of the rows; 7 of 8 partitions hold less than the mean

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 spt_skew_session.py

skew_counts.py

"""PySpark 4.2.0, local mode: measure skew as a number, from the rows each partition holds.

One million generated orders over 41 cities, one of which takes 80 % of them, are spread over 8 partitions twice:
once by a hash of the order id, once by a hash of the city id. For each spread the program prints the rows of every
partition, the largest against the mean, and the share of all rows the largest partition holds. Every number is a
row count of a fixed dataset, so two runs print the same lines.
"""

from pyspark.sql import SparkSession
from pyspark.sql.functions import spark_partition_id

spark = (SparkSession.builder
         # learn-lint-allow inclusive: PySpark 4.2.0 names the builder method that sets the cluster URL master()
         .master("local[2]")
         .appName("skew-as-a-number")
         .config("spark.ui.enabled", "false")
         .config("spark.driver.bindAddress", "127.0.0.1")
         .config("spark.driver.host", "127.0.0.1")
         .config("spark.driver.memory", "1g")
         .config("spark.sql.shuffle.partitions", "8")
         .getOrCreate())
spark.sparkContext.setLogLevel("ERROR")

print(f"PySpark {spark.version}, local mode on {spark.sparkContext.defaultParallelism} cores")
for key in ("spark.sql.adaptive.enabled", "spark.sql.adaptive.skewJoin.enabled"):
    print(f"{key} = {spark.conf.get(key)} (not set by this program)")

# Every fifth order goes to one of cities 1 to 40 in turn; the other four in five go to city 0.
orders = (spark.range(0, 1000000)
          .selectExpr("id as order_id",
                      "case when id % 5 = 0 then cast(1 + (id div 5) % 40 as int) else 0 end as city_id",
                      "cast(100 + pmod(hash(id), 900) as int) as amount"))

per_city = {row["city_id"]: row["count"] for row in orders.groupBy("city_id").count().collect()}
others = sorted({count for city, count in per_city.items() if city != 0})
print(f"\norders = {sum(per_city.values())}, cities = {len(per_city)}")
print(f"city 0 holds {per_city[0]} orders ({100 * per_city[0] / sum(per_city.values()):.1f} % of all); "
      f"each other city holds {', '.join(str(c) for c in others)}")


def rows_per_partition(df):
    """The row count of every partition of df, in partition order, with 0 for a partition that holds no rows."""
    held = {row["part"]: row["count"]
            for row in df.withColumn("part", spark_partition_id()).groupBy("part").count().collect()}
    return [held.get(part, 0) for part in range(df.rdd.getNumPartitions())]


def report(label, df):
    """Print one spread: the rows of each partition, the largest against the mean, and its share of all rows."""
    rows = rows_per_partition(df)
    mean = sum(rows) / len(rows)
    print(f"\n{label}")
    print(f"  rows per partition: {rows}")
    print(f"  largest = {max(rows)}, mean = {mean:.1f}, largest / mean = {max(rows) / mean:.2f}")
    print(f"  the largest partition holds {100 * max(rows) / sum(rows):.1f} % of the rows; "
          f"{sum(1 for r in rows if r < mean)} of {len(rows)} partitions hold less than the mean")


report("hashed on order_id into 8 partitions (a key with 1,000,000 values)", orders.repartition(8, "order_id"))
report("hashed on city_id into 8 partitions (a key with 41 values, one of them hot)", orders.repartition(8, "city_id"))

spark.stop()

Both spreads put 1,000,000 rows into 8 partitions, a mean of 125,000 each, so the largest partition of each spread says how even it is:

Spread by Largest partition Largest / mean
order_id 125,249 1.00
city_id 820,000 6.56

Hashed on the order id, the largest partition is 249 rows above the mean. Hashed on the city id, one holds 82.0 % of the rows, city 0’s 800,000 plus four small cities, so its task does the work of 6.56 average ones on any cluster. The run also printed spark.sql.adaptive.enabled and spark.sql.adaptive.skewJoin.enabled as true, though the program sets neither. What each shape needs next:

  • For a skewed sort-merge or shuffled hash join, AQE’s skew-join handling: Adaptive query execution splitting an oversized partition of a sort-merge or shuffled hash join into several tasks at runtime, switched by spark.sql.adaptive.skewJoin.enabled, which is on by default. splits the hot partition into several tasks by itself.
  • Where it cannot, salting: Adding a computed suffix to a hot key so that its rows spread over several partitions, then combining the parts in a second step that removes the suffix. adds a computed suffix to the hot key so its rows spread out, and a second aggregation removes it.
  • For spills, more shuffle partitions or narrower rows shrink each task’s share before anyone adds memory.
  • caching: Keeping a DataFrame's computed rows in executor memory or on local disk, so that later actions that read the DataFrame use those rows instead of computing it again. keeps a DataFrame that several actions reuse, and unpersist() releases it afterwards.
  • Sizing works the partition count out from the data size, then the cores and the executor memory: The heap memory of each Spark executor process, set by spark.executor.memory and shared by the tasks that run in that executor..

Checkpoint

Check: Skew as the largest partition against the mean

  1. Question 1 of 2 A stage's 8 partitions hold 30,000 rows each, except one that holds 790,000. What is the largest partition against the mean, to two decimals?

    Type a number.

    A hint

    Add the rows first, divide by 8 for the mean, then divide the largest by it.

    Show the answer: Question 1 of 2

    Answer: 6.32 times the mean (anything from 6.31 to 6.33 counts)

    The partitions hold 7 × 30,000 + 790,000 = 1,000,000 rows, so the mean is 125,000 and the ratio is 790,000 ÷ 125,000 = 6.32: one task doing more than six average tasks' work.

  2. Question 2 of 2 The recorded run printed some settings that the program never set. In PySpark 4.2.0, which of these are on by default? Choose every one.

    Choose every answer that is right.

    Show the answer: Question 2 of 2

    Answer:

    • spark.sql.adaptive.skewJoin.enabled
    • spark.sql.adaptive.enabled

    Both adaptive settings were printed as true by a program that sets neither. Salting and caching are changes a job has to make on purpose.

Practise

Six questions on the three shapes and the skew ratio, each choice explained once you answer.

Practice that adapts to you

Practise this lesson

6 questions about 7 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 6 Which three spreads of rows explain most slow stages?

    Choose one answer.

    Show the answer: Question 1 of 6

    Answer: One task far above the rest, every task too large for its memory, and thousands of near-empty tasks

    Count the rows each task of the slowest stage holds. One far above the rest is skew, all of them too large is a spill, thousands of tiny ones are a stage split too finely.

  2. Question 2 of 6 A stage runs 20,000 tasks of about 40 rows each on 16 cores. Which shape is it, and why is it slow?

    Choose one answer.

    Show the answer: Question 2 of 6

    Answer: Too many tiny tasks; starting each task costs more than the work inside it

    Thousands of near-empty tasks are the third shape. The fix is fewer, larger partitions, the opposite of the fix for a spill.

  3. Question 3 of 6 Every task of a stage reports shuffle spill (memory) and shuffle spill (disk), and the rows per task are even. Which shape is it?

    Choose one answer.

    Show the answer: Question 3 of 6

    Answer: Spills, because every task holds more than its memory takes

    Spills show in the two spill metrics of the stage page. Spread evenly over the tasks, they point at the size of each task rather than at one key.

  4. Question 4 of 6 What does a largest-partition-to-mean ratio of 1.00 say about a stage?

    Choose one answer.

    Show the answer: Question 4 of 6

    Answer: The rows are spread evenly, so no task holds much more than an average one

    A ratio near 1 is an even stage. In the run, hashing on the order id gave 1.00 and hashing on the city id 6.56.

  5. Question 5 of 6 A stage has 6 partitions holding 1,200,000 rows in all, and the largest holds 600,000. What is the largest against the mean?

    Type a number.

    A hint

    The mean is the total divided by the number of partitions.

    Show the answer: Question 5 of 6

    Answer: 3 times the mean (anything from 2.99 to 3.01 counts)

    The mean is 1,200,000 ÷ 6 = 200,000, so the largest partition is 600,000 ÷ 200,000 = 3.00 times the mean.

  6. Question 6 of 6 Orders can be spread by a hash of the customer id, with 2,000,000 customers, or by a hash of the country, with 12 countries, one of which places 70 % of the orders. Which spread gives a ratio near 1?

    Choose one answer.

    Show the answer: Question 6 of 6

    Answer: The customer id, because no single value holds a large share of the rows

    Skew lives in the key: one value with most of the rows puts them in one partition, whatever the partition count. A key with many values and no hot one gives a ratio near 1.

Skew: what adaptive execution splits, and the salting that follows when it cannot Pro: opens with a Pro, Premium or Ultimate pass

Adaptive skew handling split the hot city’s join evenly in one run and left it whole in another, on the same rows. The cases below show what decides that, and what a salt changes.

In this part:

  • What the split did to one hot partition, case by case
  • When the split steps aside, and what forcing it costs
  • Salting the hot key, and the aggregation that never needed it

1 runnable example (skew_join.py, spt_join_session.py, spt_plan.py) · about 7 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Spills and caching, decided from counts Pro: opens with a Pro, Premium or Ultimate pass

A spill and a needless cache both spend memory a task needed, and both show in counts. One run reproduces a spill and removes it two ways; the other counts what a cache saves, and when it answers with stale rows.

In this part:

  • A spill reproduced, and the two changes that removed it
  • What a cache saved, counted in rows
  • When a cache serves stale rows, and the other cases against one

2 runnable examples (cache_reuse.py, spill_partitions.py, spt_cache_session.py, spt_plan.py, spt_spill_session.py) · about 7 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Sizing partitions, cores and memory, worked from the data size Pro: opens with a Pro, Premium or Ultimate pass

Partitions, cores and executor memory follow from one number, the data a stage reads, and a few documented defaults; a model then shows why cores added to a skewed stage change almost nothing.

In this part:

  • Partitions and cores worked out from the data size
  • Memory per running task, from the documented heap layout
  • Why more cores cannot rescue a skewed stage, as a model
  • The order of changes, and why memory comes last
  • Name a slow stage's shape and the first change to make
    • Results of the sample tests
  • Key takeaways from these parts

1 diagram · 1 runnable example (Python) · 1 exercise with sample tests · about 9 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Interview questions

Warm-up: what is data skew in Spark, and how do you see it before you change anything?

Data skew is an uneven spread of rows over the partitions of a stage, nearly always because one key value is far more common than the rest. Spark sends every row of a key to the partition its hash picks, so a hot key fills one partition and its task becomes the straggler the stage waits for. You see it by counting rows per partition with spark_partition_id() and comparing the largest with the mean, or on the stage page as the one task with a far larger shuffle read. A ratio near 1 is an even stage; the hot city here gave 6.56.

Three questions carry the same diagnosis into cases with numbers:

  1. Mid to senior

    Every night, 300 million payments are joined to a merchants table too large to broadcast. Adaptive execution and its skew-join handling are on, yet one task of the join stage still runs for most of the job, holding a single merchant's rows. How do you work out why, and what do you change?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to senior

    A team caches every intermediate DataFrame of a nightly job to make it faster. Since then its widest stage spills in every task, and one report showed rows from the night before. What is going on, and what do you change?

    Model answer, Pro. First step and follow-ups

  3. Senior to staff

    A new nightly job will read about 2.4 billion rows of roughly 150 bytes each once decoded, shuffle them once and write the result. Size its shuffle partitions, cores and executors with the arithmetic shown, and say what you would check after its first run.

    Model answer, Pro. First step and follow-ups

Flashcards · 6 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. A stage has 7 of 8 tasks finished and one still running. What do you look at first?

    The rows each task holds. In the lesson that one task held 820,000 of the stage's 1,000,000 rows, and adding cores would not take a single row off it.

  2. Which three shapes explain most slow Spark stages?

    Skew, with one task far above the rest; spills, with every task too large for its memory; and thousands of near-empty tasks whose start costs more than their work.

  3. How do you put a number on skew?

    Count each partition's rows with spark_partition_id() and divide the largest by the mean. Hashed on the city id, one of 8 partitions held 82.0 % of 1,000,000 rows, 6.56 times the mean.

  4. What does adaptive query execution do, and is it on in Spark 4.2?

    It re-plans a query between stages from the sizes that finished stages report. AQE and its skew-join handling are both on by default; the skew handling covers the two joins that shuffle both sides.

  5. Where does the Spark UI report a spill?

    On the stage page, for each task, as shuffle spill (memory) and shuffle spill (disk).

  6. Which Spark cost shows up in no task count?

    A DataFrame that two actions read is computed twice unless it is cached; unpersist() frees the cache once the actions are done.

Key takeaways

  • A slow stage usually has one of three shapes: one task far above the rest, every task too large for its memory, or thousands of near-empty tasks.
  • Counting rows per partition turns skew into a number: the hot city put 820,000 of 1,000,000 rows into one of 8 partitions, 6.56 times the mean.
  • Adaptive execution (AQE) and its skew-join handling are on by default in PySpark 4.2.0, and the skew handling is documented for sort-merge and shuffled hash joins.

Terms in this lesson

caching
Keeping a DataFrame's computed rows in executor memory or on local disk, so that later actions that read the DataFrame use those rows instead of computing it again.
data skew
An uneven spread of rows over the partitions of a stage, usually because one key value is far more common than the others, so the task that holds that key does most of the stage's work.
executor memory
The heap memory of each Spark executor process, set by spark.executor.memory and shared by the tasks that run in that executor.
salting
Adding a computed suffix to a hot key so that its rows spread over several partitions, then combining the parts in a second step that removes the suffix.
skew-join handling
Adaptive query execution splitting an oversized partition of a sort-merge or shuffled hash join into several tasks at runtime, switched by spark.sql.adaptive.skewJoin.enabled, which is on by default.
storage level
The way Spark keeps a cached or persisted dataset: in memory, on disk or both, as objects or as serialized bytes, and on how many nodes.
straggler
A task that runs far longer than the other tasks of its stage, so the whole stage, and every stage after it, waits for that one task to finish.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.