Here are my two queries:
select sts_in
from sta_session
where sts_user_id=2006
AND sts_sessid!='0jitkt80gg3avere03tqk4lhi6'
order by sts_in desc limit 1;
And
select max(sts_in)
from sta_session
where sts_user_id=2006
AND sts_sessid!='0jitkt80gg3avere03tqk4lhi6';
For reference, the table looks like this:
CREATE TABLE `sta_session` (
`sta_session_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`sts_sessid` varchar(255) NOT NULL COMMENT 'PHP session ID',
`sts_user_id` int(10) unsigned NOT NULL,
`sts_in` bigint(20) NOT NULL,
`sts_out` bigint(20) NOT NULL,
`sts_ip` varchar(255) NOT NULL,
`sts_browser_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`sta_session_id`),
KEY `sts_sessid` (`sts_sessid`),
KEY `sts_user_id` (`sts_user_id`),
KEY `sts_ip` (`sts_ip`),
KEY `fk_sta_browser_id` (`sts_browser_id`),
KEY `idx_last_login` (`sts_user_id`,`sts_in`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
If I run explain on both the queries, the first one (with order by) uses my special index that I created just for this query, idx_last_login
, but the other one uses sts_user_id
.
Can the MAX query not take advantage of idx_last_login
? Why not?
I know it can use that index, because I can force it, but I suspect it's ignoring the sts_in
part of it and just searching by user id.
The EXPLAINs, in JSON format for easy reading.
explain select sts_in from sta_session where sts_user_id=2006 AND sts_sessid!='0jitkt80gg3avere03tqk4lhi6' order by sts_in desc limit 1;
[{
"id": 1,
"select_type": "SIMPLE",
"table": "sta_session",
"type": "ref",
"possible_keys": "sts_sessid,sts_user_id,idx_last_login",
"key": "idx_last_login",
"key_len": "4",
"ref": "const",
"rows": 723106,
"Extra": "Using where"
}
]
explain select max(sts_in) from sta_session where sts_user_id=2006 AND sts_sessid!='0jitkt80gg3avere03tqk4lhi6';
[{
"id": 1,
"select_type": "SIMPLE",
"table": "sta_session",
"type": "ref",
"possible_keys": "sts_sessid,sts_user_id,idx_last_login",
"key": "sts_user_id",
"key_len": "4",
"ref": "const",
"rows": 723107,
"Extra": "Using where"
}
]
Best Answer
It makes a lot of sense to me.
The MySQL Query Optimizer looks over the
WHERE
,GROUP BY
andORDER BY
clauses.Look at the first query
Which index in
sta_session
has the most columns mentioned in theWHERE
,GROUP BY
, andORDER BY
clauses ?idx_last_login
How does MySQL locate the MAX value ?
sts_user_id
inidx_last_login
index for 2006sts_in
forsts_user_id
2006sts_sessid!='0jitkt80gg3avere03tqk4lhi6'
Look at the second query
Which index in
sta_session
has the most columns mentioned in theWHERE
,GROUP BY
, andORDER BY
clauses ? Notidx_last_login
, butsts_user_id
.How does MySQL locate the MAX value ?
sts_user_id
for 2006sts_in
from the table, comparing all values ofsts_sessid
<>'0jitkt80gg3avere03tqk4lhi6'
POSSIBLE WORKAROUND
Since
sts_user_id
andidx_last_login
are duplicate indexes (because they have the same first column), you should runThere is a possibility for
idx_last_login
to be chosen and aggregatests_in
. However, there is still some traversal across the table.If you really want to get aggressive with indexing, create this one
This index might get selected and never have to touch the table because all columns (
WHERE
,ORDER BY
,MAX()
) are in the index.GIVE IT A TRY !!!