08 · Performance Optimization Basics¶
Orders has only 8 rows, so nothing here will actually feel slow — but the
diagnostic habits taught in this module apply identically at 8 rows or 8
million. We'll reason about why each technique helps using this dataset's
known numbers.
1. The Performance Recording tool¶
- Help → Settings and Performance → Start Performance Recording, use the workbook, then Stop Performance Recording — Tableau opens a generated dashboard showing a timeline of every query, layout, and rendering event with its duration.
- Events worth watching for real workbooks: "Executing Query" bars far longer than others usually mean the data source query itself (not Tableau's rendering) is the bottleneck — the fix is almost always on the data/extract side, not the worksheet design.
2. Extracts vs. live for performance¶
- An extract (
.hyperfile) pre-aggregates and compresses data into Tableau's own columnar engine — forOrders, extracting means every view (Region totals, Category totals) is served from a local already-optimized copy rather than re-querying the source file. - Extract with aggregation: Data Source page → Extract → Edit → check "Aggregate data for visible dimensions" — for a workbook that only ever needs Region/Category-level totals (2210/3750/920 and 4050/2650/180), this option pre-collapses the 8 row-level records into the 3+3 aggregate rows actually used, shrinking the extract further.
3. Filters: extract filters vs. context filters vs. quick filters¶
- An extract filter (Data Source page → Extract → Filters) removes
rows before they ever enter the
.hyperfile — e.g. filtering toOrder Date >= 2024-02-01at extract time would drop orders 1001 and 1002 (Jan) permanently from that extract, reducing every downstream query's scan size. - A context filter (right-click a filter pill → Add to Context) forces that filter to run first, before other filters/table calcs, which both fixes certain table-calc-ordering bugs (Level 2 Module 4) and, for a large dataset, lets Tableau cache the reduced result set once instead of recomputing it for every other filter change.
- Quick filters (a filter card left on the dashboard for viewers) are
the most expensive per-interaction — each click re-queries — so keep
the number of quick filters and their cardinality (distinct value
count) low;
Region(3 distinct values) is a cheap quick filter, a hypotheticalOrder ID(8, or millions in a real dataset) is not.
4. Reducing marks and calculation complexity¶
- A view rendering one mark per
Order ID(8 marks here) is cheap; the same pattern at real scale — one mark per row in a million-row table — is a common performance mistake. Prefer aggregating to Region/Category (3–4 marks) whenever the analysis question doesn't require row-level detail. - Nested LOD expressions (Level 2 Module 1) recompute per underlying row
before aggregating — a
{FIXED [Region]: SUM([Sales])}over 8 rows is instant, but the same construct over a large fact table forces a full table scan per LOD, so prefer a pre-aggregated extract (Section 2) when an LOD's underlying grain is much finer than the view needs.
5. Verifying an optimization actually helped¶
- Before/after check: extract-filter the workbook to
Order Date >= 2024-02-01(Section 3.1) and confirmSUM(Sales)now reads 60 + 800 + 2200 + 950 + 120 + 1100 = 5230 (orders 1003–1008), not 6880 — this confirms the filter genuinely reduced the row set rather than just hiding rows visually. - Any optimization step should be paired with exactly this kind of before/after total check — performance work that silently changes your numbers is a correctness bug, not a speed win.
How It Actually Works¶
Every technique in this module targets a specific stage of the query pipeline built up across Level 1–2 — naming the stage each one hits is what turns "try this, it's usually faster" into a predictable diagnosis:
- Extract filters (Section 3.1) act at the earliest possible point —
before the
.hyperfile is even written — so they shrink the data every later stage (Stage 1'sGROUP BYquery, any LOD subquery, any table calc's Stage 2 array) has to process. Filtering toOrder Date >= 2024-02-01removes rows 1001/1002 permanently from that extract, soSUM(Sales)recomputed from the remaining 6 rows (60+800+2200+950+120 +1100) correctly comes out to 5230 — a smaller number because fewer rows exist to sum, not because of any display-side rounding. - Context filters (Section 3.2) act at Stage 1 but late in it: they
force their
WHERE/subquery clause to materialize as an intermediate temp table before every other filter and every LOD{FIXED}subquery runs — which is why they both fix table-calc ordering bugs (Level 2 Module 4, Section 7) and speed things up: Tableau can cache that one materialized intermediate result and reuse it across multiple other filter changes instead of re-scanning the full extract each time. - Extract aggregation (Section 2.2) changes what's physically stored
in the
.hyperfile itself — instead of storing all 8 raw rows, it pre-computes and stores only the Region/Category-levelGROUP BYresult (3 or 4 rows), so every subsequent Stage-1 query at that same or coarser grain reads a table that's already the size of its own answer — but it also means an LOD expression needing finer detail (like Level 2 Module 1's Order-ID-level INCLUDE) can no longer be computed correctly from that extract, since the row-level data it needs no longer exists. - Marks count and LOD nesting (Section 4) both affect Stage-1/Stage-2
compute cost directly: more marks means a larger Stage-1 result set for
Stage 2 (table calcs) and the renderer to walk; a
{FIXED}LOD's subquery (Level 2 Module 1) re-scans the underlying table at its specified grain every time it's invalidated, so nesting several fine-grained LODs on a large fact table multiplies the number of full subquery scans a single sheet triggers.
Cheat sheet¶
| Technique | Effect |
|---|---|
Extract (.hyper) |
Local, pre-optimized copy vs. live re-query |
| Extract with aggregation | Collapses to only the dimensions used |
| Extract filter | Drops rows before the extract is built |
| Context filter | Runs first; can be cached; fixes calc-order bugs |
| Fewer marks / less granularity | Less rendering + query work |
| Performance Recording | Diagnoses where time is actually spent |
Exercise¶
Using an extract filter of Order Date >= 2024-03-01, list which Order IDs
remain (1005, 1006, 1007, 1008) and hand-verify the new SUM(Sales) total
is 2200+950+120+1100 = 4370.