Exercise 3: A Range Query Can't Use the Index — Possible Solution ==================================================================== THE TEST ------------------------------ range_where = ('id', '>', N_CUST - 5) # WHERE id > 1495 range_result = cat.select('customers', range_where) range_naive = cat.select_naive('customers', range_where) indexed_cols = {c for (t, c) in cat.indexes if t == 'customers'} plan_used = choose_where_plan(range_where, indexed_cols) RESULT ------------------------------ WHERE id > 1495 -> plan chosen: scan results match: True Even though customers.id has a real, working index built on it, choose_where_plan() falls back to a full scan for this query. Both paths still return the same correct set of rows -- the plan choice only affects performance, not correctness -- but the "smart" path gets no benefit at all here. WHY THE PLANNER FALLS BACK TO A SCAN ------------------------------ choose_where_plan()'s own logic is deliberately narrow: def choose_where_plan(where, indexed_columns): col, op, value = where if op == '=' and col in indexed_columns: return ('index', col, value) return ('scan', None, None) The condition explicitly checks op == '=' -- for any other operator, including '>' or '<', it falls straight through to the scan branch, regardless of whether an index exists on that column at all. This isn't an oversight specific to this chapter; it's inherited directly from Course 1's own Storage & Query Fundamentals Chapter 9, where the same restriction was first introduced and never revisited since. WHY THIS IS A REAL LIMITATION, NOT A NECESSARY ONE ------------------------------ The underlying B-tree (built in dbengine1 Chapters 5-6) stores its own keys in sorted order -- that's the entire point of a B-tree's own structure. A real range query like "id > 1495" could, in principle, walk the tree to find the first key greater than 1495 and then follow sibling/in-order links to collect every key after it, entirely avoiding a full table scan. btree_search() as built in this course only supports finding a single, exact key -- it has no equivalent "find the first key greater than X, then continue" operation. Adding real range-scan support to the B-tree, and teaching the planner to recognize '>'/'<'/'>='/'<=' as index-eligible operators, would both be required to fix this -- neither one exists in this engine as built. WHY THIS WORKS AS AN ANSWER ------------------------------ Confirming BOTH that the plan choice is genuinely "scan" (not silently falling back to something incorrect) AND that the results still match the naive baseline demonstrates the gap is purely a missed performance opportunity, not a correctness bug -- and tracing the limitation back to a specific, named method (btree_search()'s own single-key-only design) rather than a vague "it doesn't support ranges" pinpoints exactly what would need to change to fix it.