Teach Lessons
Interactive, offline-first HTML lessons that animate MySQL 8.4 and MariaDB 11.x internals with correct cost models.
Quick start
myflames teach # list all lessons
myflames teach btree -o btree.html && open btree.html
Each lesson is a single self-contained HTML file. No external scripts, stylesheets, or fonts. Drop it in Slack, attach to a ticket, or email it — it just works offline.
All 14 lessons
Storage internals
B+tree Lookup
How InnoDB finds a row: clustered PK vs covering secondary vs non-covering secondary. Move the row-count slider from 10 to 1 billion and watch the tree height change.
InnoDB Buffer Pool LRU
Why MySQL's midpoint-insertion LRU survives full-scan pollution while textbook LRU gets wiped. 3-act story: hot set → scan arrives → hot queries return.
Join algorithms
Block Nested Loop (BNL)
MariaDB's default join algorithm. Watch join_buffer_size decide how many times the inner table is rescanned. Includes warning: MySQL removed BNL in 8.0.20.
Hash Join
Build phase (hash departments into buckets), probe phase (find each employee's department), and grace-hash spill when join_buffer_size overflows.
BNL vs Hash Join
Side-by-side comparison with shared sliders. See the asymptotic difference at scale: BNL grows with blocks × inner, hash stays at build + probe.
Nested Loop Join (Operator)
Dedicated operator view for EXPLAIN Nested loop nodes. Focuses on outer-driver + inner-probe behavior and O(n × m) growth.
Query optimization
Filesort
How MySQL sorts when there is no index: sort_buffer_size fills, sorted runs spill to tmpdir, then a k-way merge produces the final result. Bigger buffer = fewer runs = less I/O.
Temporary Tables
Watch GROUP BY fill a MEMORY temp table, hit min(tmp_table_size, max_heap_table_size), and convert to on-disk InnoDB. That cliff is why your query suddenly slows down.
Index Condition Pushdown (ICP)
Side-by-side: without ICP, every row is fetched then filtered. With ICP, the storage engine checks trailing index columns before fetching — saving unnecessary clustered-index lookups.
Index Merge
Two separate index scans combined via union, intersection, or sort-union. See how MySQL avoids a full table scan by merging row-ID sets from multiple indexes.
Full Table Scan
What a full table scan actually means: every row is read, then filtered. Compare O(n) scan work with indexed access O(log n + k) as selectivity changes.
Non-Unique Key Lookup
What “Non-Unique Key Lookup” means in the diagram: one key/range can match many entries, then non-covering lookups fetch base rows by row-id.
Unique Key Lookup
Single-row index lookup path (eq_ref/const style). Shows exact-key traversal and covering vs non-covering fetch behavior.
Filter Operator
What a Filter stage means: every incoming row is evaluated against the predicate, only matching rows continue to parent stages.
Lesson features
- In-page sliders — change parameters and see the cost model update instantly. No CLI flags, no re-running.
- Animated SVG stage — Play/Pause, Speed (0.25x–4x), YouTube-style scrubber, Reset button.
- Phase navigation — clickable sidebar listing all animation phases. Click to jump to any phase.
- Cost readout — live numeric displays with (?) help tooltips written at a 10th-grade reading level.
- Complexity chart — log-log plots showing how the algorithm scales (most lessons).
- Learn more — collapsible
<details>block with deeper context and MySQL documentation sources. - Accessibility — ARIA labels, keyboard navigation,
prefers-reduced-motionsupport. - Offline-first — no external scripts, stylesheets, or fonts. Single HTML file, works anywhere.
Python API
from myflames.teach import render_lesson, LESSONS
# List available lessons
for name, info in LESSONS.items():
print(f"{name}: {info['summary']}")
# Render to HTML string
html = render_lesson("btree")
with open("btree.html", "w") as f:
f.write(html)