CREATE TABLE `files` (
`did` int(10) unsigned NOT NULL DEFAULT '0',
`filename` varbinary(200) NOT NULL,
`ext` varbinary(5) DEFAULT NULL,
`fsize` double DEFAULT NULL,
`filetime` datetime DEFAULT NULL,
PRIMARY KEY (`did`,`filename`),
KEY `fe` (`filetime`,`ext`), -- This?
KEY `ef` (`ext`,`filetime`) -- or This?
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
There are a million rows in the table. The filetimes are mostly distinct. There are a finite number of ext
values. So, filetime
has a high cardinality and ext
has a much lower cardinality.
The query involves both ext
and filetime
:
WHERE ext = '...'
AND filetime BETWEEN ... AND ...
Which of those two indexes is better? And why?
First, let's try
FORCE INDEX
to pick eitheref
orfe
. The timings are too short to get a clear picture of which is faster, but `EXPLAIN shows a difference:Forcing the range on
filetime
first. (Note: The order inWHERE
has no impact.)Forcing the low-cardinality
ext
first:Clearly, the
rows
saysef
is better. But let's check with the Optimizer trace. The output is rather bulky; I'll show only the interesting parts. NoFORCE
is needed; the trace will show both options then pick the better....
...
With
fe
(range column first), the range could be used, but it estimated scanning through 16684 rows fishing forext='gif'
.With
ef
(low cardinalityext
first), it could use both columns of the index and drill down more efficiently in the BTree. Then it found an estimated 538 rows, all of which are useful for the query -- no further filtering needed.Conclusions:
INDEX(filetime, ext)
used only the first column.INDEX(ext, filetime)
used both columns.=
tests first in the index regardless of cardinality.("Using index condition" means that the Storage Engine (InnoDB) will use columns of the index beyond the one used for filtering.")