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

myflames teach btree
MySQL 8.4MariaDB 11.4

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

myflames teach lru
MySQL 8.4

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)

myflames teach bnl
MariaDB 11.x

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

myflames teach hash
MySQL 8.4

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

myflames teach join
MySQL 8.4MariaDB 11.x

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)

myflames teach nested_loop
MySQL 8.4MariaDB 11.4

Dedicated operator view for EXPLAIN Nested loop nodes. Focuses on outer-driver + inner-probe behavior and O(n × m) growth.

Query optimization

Filesort

myflames teach filesort
MySQL 8.4MariaDB 11.4

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

myflames teach tmp
MySQL 8.4

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)

myflames teach icp
MySQL 5.6+MariaDB 5.3+

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

myflames teach index_merge
MySQL 5.1+MariaDB 5.1+

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

myflames teach full_scan
MySQL 8.4MariaDB 11.4

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

myflames teach non_unique_lookup
MySQL 8.4MariaDB 11.4

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

myflames teach unique_lookup
MySQL 8.4MariaDB 11.4

Single-row index lookup path (eq_ref/const style). Shows exact-key traversal and covering vs non-covering fetch behavior.

Filter Operator

myflames teach filter
MySQL 8.4MariaDB 11.4

What a Filter stage means: every incoming row is evaluated against the predicate, only matching rows continue to parent stages.

Lesson features

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)