Exercise 2: An Index Changes How, Never What — Possible Solution ==================================================================== THE TEST ------------------------------ where_test = ('id', '=', 777) naive_hits = cat.select_naive('customers', where_test) # always full scan smart_hits = cat.select('customers', where_test) # uses the index RESULT ------------------------------ naive (always scan) result: [(777, 'Customer777')] smart (uses index) result: [(777, 'Customer777')] Both calls return the exact same single row. WHY THE TWO CODE PATHS PRODUCE IDENTICAL RESULTS ------------------------------ select_naive() does the simplest possible thing: iterate every row in customers and keep the ones matching the WHERE condition: return [row for row in self.tables[table_name] if OPS[where[1]](row[col_idx], where[2])] select() does something structurally different -- it calls choose_where_plan(), which for an '=' operator on an indexed column returns ('index', col, value), and then does a real btree_search() against the actual B-tree built by create_index() to find the row's own location directly, without looking at any other row at all. These are genuinely two different ALGORITHMS -- one touches every row, the other touches (at most) a handful of B-tree nodes on the path to the one matching key. WHY THIS HAS TO PRODUCE THE SAME ANSWER, NOT JUST HAPPEN TO ------------------------------ The index was built directly from the real data (create_index() scans the table and inserts every row's own key into the B-tree at registration time), and nothing has modified customers since. Both code paths are answering the exact same question -- "which rows have id=777" -- against the exact same underlying data; only the MECHANISM for finding the answer differs. An index is a lookup shortcut, not an alternate source of truth: if using it ever produced a different answer than a full, honest scan of the real data, that would mean the index itself had drifted out of sync with the table -- exactly the kind of consistency bug this course's own Chapter 1 opened with, just appearing here at the query-planning layer instead of the write layer. WHY THIS WORKS AS AN ANSWER ------------------------------ Directly comparing the two code paths' own results, rather than just trusting that "using an index is correct because it's faster," confirms the planner's own choice between them is purely a performance decision -- swapping which one runs is safe precisely because both are provably answering the identical query against the identical data.