patternsqlMinor
Why is ORDER BY LIMIT 1 so much faster than MAX?
Viewed 0 times
whyordermuchlimitthanfastermax
Problem
Here are my two queries:
And
For reference, the table looks like this:
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,
Can the MAX query not take advantage of
I know it can use that index, because I can force it, but I suspect it's ignoring the
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",
"typ
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",
"typ
Solution
It makes a lot of sense to me.
The MySQL Query Optimizer looks over the
Look at the first query
Which index in
How does MySQL locate the MAX value ?
Look at the second query
Which index in
How does MySQL locate the MAX value ?
POSSIBLE WORKAROUND
Since
There is a possibility for
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 (
GIVE IT A TRY !!!
The MySQL Query Optimizer looks over the
WHERE, GROUP BY and ORDER BY clauses.Look at the first query
select sts_in
from sta_session
where sts_user_id=2006
AND sts_sessid!='0jitkt80gg3avere03tqk4lhi6'
order by sts_in desc limit 1;Which index in
sta_session has the most columns mentioned in the WHERE, GROUP BY, and ORDER BY clauses ? idx_last_loginHow does MySQL locate the MAX value ?
- Traverse
sts_user_idinidx_last_loginindex for 2006
- Go to the Last Index Entry for
sts_inforsts_user_id2006
- Scroll backwards until
sts_sessid!='0jitkt80gg3avere03tqk4lhi6'
- Limit result to 1 row
Look at the second query
select max(sts_in)
from sta_session
where sts_user_id=2006
AND sts_sessid!='0jitkt80gg3avere03tqk4lhi6';Which index in
sta_session has the most columns mentioned in the WHERE, GROUP BY, and ORDER BY clauses ? Not idx_last_login, but sts_user_id.How does MySQL locate the MAX value ?
- Full Index Range Scan
sts_user_idfor 2006
- Aggregate
sts_infrom the table, comparing all values ofsts_sessid<>'0jitkt80gg3avere03tqk4lhi6'
POSSIBLE WORKAROUND
Since
sts_user_id and idx_last_login are duplicate indexes (because they have the same first column), you should runALTER TABLE sta_session DROP INDEX sts_user_id;There is a possibility for
idx_last_login to be chosen and aggregate sts_in. However, there is still some traversal across the table.If you really want to get aggressive with indexing, create this one
ALTER TABLE sta_session ADD INDEX everything_and_the_kitchen_sink_index
(sts_user_id,sts_in,sts_sessid);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 !!!
Code Snippets
select sts_in
from sta_session
where sts_user_id=2006
AND sts_sessid!='0jitkt80gg3avere03tqk4lhi6'
order by sts_in desc limit 1;select max(sts_in)
from sta_session
where sts_user_id=2006
AND sts_sessid!='0jitkt80gg3avere03tqk4lhi6';ALTER TABLE sta_session DROP INDEX sts_user_id;ALTER TABLE sta_session ADD INDEX everything_and_the_kitchen_sink_index
(sts_user_id,sts_in,sts_sessid);Context
StackExchange Database Administrators Q#107082, answer score: 7
Revisions (0)
No revisions yet.