Adding three separate single-column indexes on tenant_id , status , and created_at will not make a multi-filter dashboard query fast—in fact, putting columns in the wrong order inside a composite B-Tree index stops the database engine from narrowing the search range right after the first range predicate. To eliminate disk-heavy heap fetches and in-memory filesort operations in PostgreSQL and MySQL, you must order composite index columns by the Equality -> Sort -> Range (ESR) rule rather than simply listing the most selective column first. Below is how composite B-Tree traversal actually works on disk, with real EXPLAIN ANALYZE plans from production workloads.
Why Separate Single-Column Indexes Lose to One Composite Index
When our engineering team at Loop Origin audits a slow SaaS or e-commerce database, we almost always find tables where every foreign key and status column has its own individual index, yet a basic orders query takes 850 milliseconds.…