Module: Operating Query Engines | Duration: 20 min hands-on | Lesson: 1 of 14
Priya is now on-call for four engines: Trino, ClickHouse, Druid, and DuckDB. A query is slow on each, in turn, and each prints a completely different EXPLAIN: Trino shows fragments and distribution, ClickHouse shows a pipeline of processors, Druid shows native JSON, DuckDB shows a tree of operators. Four formats, four vocabularies, one tired engineer at 3am.
Here's the freeing realization: they're all describing the same handful of things. Scan, filter, join, aggregate, exchange, sort. Once you can map any engine's EXPLAIN onto that shared mental model from Query Engine Foundations, the format stops mattering. This lesson builds that map, and brings up the lab you'll use for the rest of the course.
2. Concept Explanation
Every query engine's EXPLAIN, however it's formatted, answers the same questions. Learn the questions, and any format becomes readable.
The five questions every EXPLAIN answers
- What's read, and how much is pruned? The scan, and whether filters/partitions/indexes cut it down before reading. (ClickHouse: granules selected. Trino: pushed-down predicates + dynamic filters. Druid: which segments. DuckDB: which row groups.)
- What's pushed down vs done in the engine? Did the filter/projection/aggregation happen at the source/storage, or after reading? (Especially Trino connectors; also ClickHouse
PREWHERE.) - How are joins done and distributed? Hash vs sort-merge; broadcast vs partitioned/shuffle. (The foundations join lessons, made concrete per engine.)
- Where are the pipeline breakers? The sorts, hash builds, and global aggregations where memory concentrates and streaming stops.
- What's the parallelism? How many lanes/tasks run each stage. (ClickHouse
(xN); Trino tasks per stage; etc.)
The same operators, different words
| Concept | Trino | ClickHouse | Druid | DuckDB |
|---|---|---|---|---|
| Read data | TableScan | ReadFromMergeTree | scan/segment scan | SEQ_SCAN |
| Filter | Filter / pushed predicate | PREWHERE/WHERE, granule skip | filter spec | FILTER |
| Join | Join (PARTITIONED/REPLICATED) | hash join | limited join | HASH_JOIN |
| Aggregate | Aggregate | Aggregating | groupBy/timeseries | HASH_GROUP_BY |
| Data movement | exchange (fragment boundary) | (single node) / Distributed | broker gather | (single node) |
The labels differ; the operators are the ones you already know. EXPLAIN literacy is translation, not relearning.
Two EXPLAIN modes, everywhere
Almost every engine has two flavors, and you use both:
- Static plan (
EXPLAIN): the shape the optimizer chose, before running. Answers "what will it do?" - Analyzed/profiled (
EXPLAIN ANALYZEin Trino/DuckDB,EXPLAIN PIPELINE+ query log in ClickHouse, query metrics in Druid): the real timings after running. Answers "where did the time actually go?"
The method, which the next lesson formalizes, is always: read the static plan for structure, then the analyzed plan for where time went.
Aha: You don't need to learn four EXPLAIN formats, you need to learn the five questions every plan answers and translate each engine's dialect into them. A ClickHouse (x8), a Trino task count, and a DuckDB thread count are the same question: "how parallel is this?" Stop reading EXPLAIN as four languages and start reading it as one set of questions with four accents.
3. Worked Example
Bring up the lab and read the same query's plan through two engines.
Bring up the lab (one time, shared across all courses):
Verify ClickHouse and Trino are up over the same data:
Now read one query's plan in both engines. The data (tws.events) is identical; only the EXPLAIN dialect differs.
Map them onto the five questions: in ClickHouse's EXPLAIN PIPELINE, find the (xN) (parallelism) and the Aggregating (aggregate); in Trino's plan, find the TableScan (what's pushed to ClickHouse), the Aggregate, and the fragment boundaries (exchanges). Same five questions, two accents. Do this once and every future EXPLAIN is just translation.
4. Your Turn
Exercise: Translate across engines.
- A ClickHouse
EXPLAIN PIPELINEshows(x1)on the aggregation; a Trino plan shows one task on the aggregate stage. Which of the five questions is each answering, and what's the shared concern? - You see a Trino
Filternode above aTableScan(not pushed). What's the ClickHouse analog you'd look for to check if filtering happened early? - Map these to the shared operator: ClickHouse
ReadFromMergeTree, TrinoTableScan, DuckDBSEQ_SCAN. - For "where will this query use the most memory?", which of the five questions do you read, and what operators are you hunting for in any engine?
5. Real-World Application
EXPLAIN literacy across engines is the core skill of multi-engine on-call. A platform team running Trino for federation, ClickHouse for product analytics, and Druid for user-facing dashboards needs engineers who can read any of their plans, and the only sane way to do that is the shared mental model, not memorizing four formats. The five questions are the same diagnostic checklist regardless of which pager went off.
This lesson is deliberately the gateway to the whole Operations track. Every later lesson, profiling, memory, concurrency, incidents, starts from "read the plan." Build the translation habit now and the rest of the course is applying it under production pressure. It's also why this skill appears in both S6.1 (as a concept) and here (as a per-engine operational skill): the concept and the craft reinforce each other.
6. Recap + Bridge
Every engine's EXPLAIN answers the same five questions: what's scanned/pruned, what's pushed down, how joins distribute, where the pipeline breakers are, and how parallel it is. The operators are the ones from Query Engine Foundations wearing different labels. Read the static plan for structure, the analyzed plan for timings. EXPLAIN literacy is translation, not relearning.
Reading a plan is step one. Turning it into a fix needs method. Next: Profiling a Slow Query, a methodology that works before you reach for any tool.