mysql 取最大最小值之 optimized away

Posted by Vincent on May 29, 2011

在取mysql主键最大最小值时,mysql会使用最优方式 SELECT tables optimized away

官方解释
SELECT tables optimized away:当我们使用某些聚合函数来访问存在索引的某个字段时,MySQL Query Optimizer 会通过索引直接一次定位到所需的数据行完成整个查询。当然,前提是在 Query 中不能有 GROUP BY 操作。如使用MIN()或MAX()的时候

[cc lang='sql']root@wap 06:57:32>explain select max(id) from tmp_xf;
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
[/cc]
我们知道,innodb引擎的表是索引组织表,按照主键顺序存储。每个索引的都包含主键用来做指针定位到具体的记录。

[cc lang='sql']dbaeyes 09:48:10>show create table tmp_xf\G
*************************** 1. row ***************************
Table: tmp_xf
Create Table: CREATE TABLE `tmp_xf` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT ,
`account` varchar(50) NOT NULL ,
`status` int(11) NOT NULL ,
`activity_id` int(11) NOT NULL,
`gmt_create` datetime NOT NULL,
`gmt_modified` datetime NOT NULL ,
PRIMARY KEY (`id`),
KEY `status` (`status`)
) ENGINE=InnoDB AUTO_INCREMENT=990001 DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
[/cc]
表记录99w

select max(id) from tmp_xf where status = 0; 但是这个sql并不能使用

optimized away
[cc lang='sql']dbaeyes 09:48:19>explain select max(id) from tmp_xf where status = 0;
+----+-------------+--------+------+---------------+--------+---------+-------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+--------+---------+-------+--------+-------------+
| 1 | SIMPLE | tmp_xf | ref | status | status | 4 | const | 494509 |Using index |
+----+-------------+--------+------+---------------+--------+---------+-------+--------+-------------+[/cc]

sql直接使用了索引,而且扫描了整个索引才获取到需要的数据,这个效率是非常低的。从执行计划可以看到扫描了49w+

dbaeyes 09:48:30>select max(id) from tmp_xf where status = 0;
+---------+
| max(id) |
+---------+
| 990000 |
+---------+
1 row in set (1.89 sec)

下面尝试另外一种方式,我们创建 包含了 status,id的索引,既把id显示的放在索引中,这样id在索引中肯定是排序好的。

[cc lang='sql'] root@wap 07:21:36>explain select max(id) from tmp_xf where status = 0;
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
1 row in set (0.00 sec)

root@wap 07:21:54>select max(id) from tmp_xf where status = 0;
+---------+
| max(id) |
+---------+
| 990000 |
+---------+
1 row in set (0.00 sec)
[/cc]

--eof--


This work is licensed under a CC A-S 4.0 International License.