MySQL Composite Indexes
Reason about the index’s leading columns instead of assuming any included column is equally searchable.
How it works
A compound B-tree index orders a tuple of columns. Its leading fields determine which prefixes and ranges can be used efficiently. The example filters a depot by equality, then a cost range and a deterministic order. An index beginning with depot_id and unit_cost is a plausible candidate for that access pattern. The tiny fixture still does not guarantee its use; inspect plans with representative data rather than teaching index rules as absolute promises.
Run in a disposable MySQL lab
Use Oracle MySQL 8.4 with InnoDB, not Bhylu’s SQLite playground. The examples were reviewed on MySQL 8.4.8. XAMPP may provide MariaDB, which has different feature and collation behaviour. Check your actual server before running the script. These lessons do not require a change to Bhylu’s PHP, Apache or normal database service.
- On a separate lab instance, create the empty bhylu_mysql_lab schema. Stop if it already exists; do not overwrite an existing database.
- Select that schema and import the complete repair-parts seed once. It sets the documented session mode, utf8mb4 collation, UTC and English date-name locale.
- Run this lesson in a fresh copy of the seed, not after another lesson’s writes. Use the command-line client or a compatible editor. DELIMITER lines are client instructions for stored-program examples.
Download this complete lesson script. Its setup is the linked seed; review the dataset before changing it. Administrative and destructive examples are restricted to the specifically named disposable objects. Every script repeats the session settings because each new connection has its own session. No MySQL browser runner is currently available.
Example
SET NAMES utf8mb4 COLLATE utf8mb4_0900_ai_ci;
SET SESSION sql_mode = 'STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';
SET SESSION time_zone = '+00:00';
SET SESSION lc_time_names = 'en_US';
CREATE INDEX ix_parts_depot_cost ON parts(depot_id,unit_cost,id);
SELECT id,name FROM parts
WHERE depot_id = 1 AND unit_cost >= 2
ORDER BY unit_cost,id;
Expected result
1 | Canvas patch 2 | Brass hinge
The equality narrows the depot and the range orders eligible costs. Wrapping an indexed date in a function can prevent a useful direct range, so prefer an equivalent half-open predicate when it preserves the required semantics. Collation, type conversion and selectivity also influence usable access paths. Keep the query’s correctness independent of whichever plan is chosen.
Use the official MySQL 8.4 reference for statement contracts and version details.