Master the leftmost-prefix rule, covering indexes, and the pitfalls that make an index invisible to the planner.
Open this lesson in KodokonA composite index orders rows across multiple columns, in the declared order. The decisive rule is the leftmost prefix: an index on (a, b) can serve a filter on a, or on a and b, but never on b alone. The column order is therefore a design choice, not a detail. First create the dataset below.
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
department_id INTEGER,
salary INTEGER NOT NULL
);
INSERT INTO employees
(id, name, department_id, salary)
VALUES
(1, 'Ada', 1, 65000),
(2, 'Grace', 1, 72000),
(3, 'Alan', 2, 58000),
(4, 'Edsger', 1, 90000);Let's create an index on (department_id, salary). A filter that starts with department_id triggers a SEARCH. But a filter on salary only breaks the leftmost prefix: the planner cannot jump straight to the right rows and falls back to a SCAN. Compare the two plans.
CREATE INDEX idx_dept_salary
ON employees (department_id, salary);
-- Leftmost prefix present: index used
EXPLAIN QUERY PLAN
SELECT id FROM employees
WHERE department_id = 1
AND salary > 60000;
-- SEARCH ... USING INDEX idx_dept_salary
-- Leading column missing: index ignored
EXPLAIN QUERY PLAN
SELECT id FROM employees
WHERE salary > 60000;
-- SCAN employeesA covering index contains every column read by the query. The planner then answers directly from the index, without opening the table: that's the meaning of USING COVERING INDEX. Here, the index (department_id, salary) covers a query that reads only those two columns. Remember that the id (the rowid) is implicitly present in every index, so it too is covered for free.
-- Every column read is in the index
EXPLAIN QUERY PLAN
SELECT department_id, salary
FROM employees
WHERE department_id = 1;
-- SEARCH employees USING COVERING INDEX
-- idx_dept_salary (department_id=?)(department_id, salary), which query CANNOT use it?email?