MySQL索引实战 & 执行计划
一、执行计划(只是自己理解)
1,id):
id 相同,执行顺序由上到下,按照我的理解,通常发生于子查询;
id 不同,如果是子查询,id的序号会递增,id越大则优先级越高,越先会被执行;
id 既不同又相同,id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行;
2,select_type):
simple:简单的select查询,查询中不包含子查询或者union;
primary:查询中包含任何复杂的子部分,最外层查询则被标记为primary;
subquery:在select 或 where列表中(除了from字句中包含的子查询外)包含了子查询,可能是subquery;
derived:表示用了临时表;
union result:从union表获取结果的select;
3,table):
显示的查询表名,如果查询使用了别名,那么这里显示的是别名;
如果不涉及对数据表的操作,那么这显示为null;
如果显示为尖括号括起来的<derived N>就表示这个是临时表,后边的N就是执行计划中的id,表示结果来自于这个查询产生;
如果是尖括号括起来的<union M,N>,与<derived N>类似,也是一个临时表,表示这个结果来自于union查询的id为M,N的结果集;
4,type)访问数据的方式:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
system:可以忽略不计;
const:使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const;
eq_ref:看不懂;
ref:普通的索引扫描方式;
all:这个就是全表扫描数据文件,然后再在server层进行过滤返回符合要求的记录。
possible_keys:查询可能使用到的索引都会在这里列出来;如果为NULL,说明没有WHERE条件时查询优化器无法通过索引检索数据。
key:查询真正使用到的索引,select_type为index_merge时,这里可能出现两个以上的索引,其他的select_type这里只会出现一个。
rows:这里是执行计划中估算的扫描行数,不是精确值。
extra:这个列可以显示的信息非常多,有几十种,常用的有:
using filesort:排序时无法使用到索引时,就会出现这个。常见于order by和group by语句中。
using index:查询时不需要回表查询,直接通过索引就可以获取查询的数据(表明使用了覆盖索引)。
Using index condition, Using where; 用了索引,但是需要回表查找;(目前我的理解是这样)
二、实战
基本哦:
SHOW INDEX FROM test_emp; +----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | test_emp | 0 | PRIMARY | 1 | id | A | 3 | NULL | NULL | | BTREE | | | | test_emp | 1 | idx_age_name | 1 | age | A | 3 | NULL | NULL | YES | BTREE | | | | test_emp | 1 | idx_age_name | 2 | name | A | 3 | NULL | NULL | YES | BTREE | | | +----------+------------+--------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ rows in set (0.00 sec) // 使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const; mysql> EXPLAIN SELECT * FROM test_emp WHERE id = '2'; +----+-------------+----------+-------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+-------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | test_emp | const | PRIMARY | PRIMARY | 4 | const | 1 | NULL | +----+-------------+----------+-------+---------------+---------+---------+-------+------+-------+ row in set (0.01 sec) // type 为 ref,说明用了普通的索引扫描方式 // Using index condition, Using where; 用了索引,但是需要回表查找;(目前我的理解是这样) mysql> EXPLAIN SELECT * FROM test_emp WHERE age = '22' AND `name` = '111'; +----+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+ | 1 | SIMPLE | test_emp | ref | idx_age_name | idx_age_name | 773 | const,const | 1 | Using index condition | +----+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+ row in set (0.00 sec) // 说明如果都是等号的话,顺序是没有问题的 mysql> EXPLAIN SELECT * FROM test_emp WHERE `name` = '111' AND age = '22'; +----+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+ | 1 | SIMPLE | test_emp | ref | idx_age_name | idx_age_name | 773 | const,const | 1 | Using index condition | +----+-------------+----------+------+---------------+--------------+---------+-------------+------+-----------------------+ row in set (0.00 sec) // 好像这个也没有问题 mysql> EXPLAIN SELECT * FROM test_emp WHERE age = '22'; +----+-------------+----------+------+---------------+--------------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+--------------+---------+-------+------+-------+ | 1 | SIMPLE | test_emp | ref | idx_age_name | idx_age_name | 5 | const | 1 | NULL | +----+-------------+----------+------+---------------+--------------+---------+-------+------+-------+ row in set (0.00 sec) // 这个就没有办法了,因为age在前面 mysql> EXPLAIN SELECT * FROM test_emp WHERE `name` = '111'; +----+-------------+----------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | test_emp | ALL | NULL | NULL | NULL | NULL | 3 | Using where | +----+-------------+----------+------+---------------+------+---------+------+------+-------------+ row in set (0.00 sec) // age和name反了 mysql> EXPLAIN SELECT * FROM test_emp WHERE `name` = '111' ORDER BY age; +----+-------------+----------+------+---------------+------+---------+------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+------+---------+------+------+-----------------------------+ | 1 | SIMPLE | test_emp | ALL | NULL | NULL | NULL | NULL | 3 | Using where; Using filesort | +----+-------------+----------+------+---------------+------+---------+------+------+-----------------------------+ row in set (0.00 sec) // 顺序顺序,age在前,name在后 mysql> EXPLAIN SELECT * FROM test_emp WHERE `age` = '111' ORDER BY `name`; +----+-------------+----------+------+---------------+--------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+------+---------------+--------------+---------+-------+------+-------------+ | 1 | SIMPLE | test_emp | ref | idx_age_name | idx_age_name | 5 | const | 1 | Using where | +----+-------------+----------+------+---------------+--------------+---------+-------+------+-------------+ row in set (0.00 sec) // 顺序顺序,age在前,name在后 mysql> EXPLAIN SELECT * FROM test_emp GROUP BY age ORDER BY `name`; +----+-------------+----------+-------+---------------+--------------+---------+------+------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+----------+-------+---------------+--------------+---------+------+------+---------------------------------+ | 1 | SIMPLE | test_emp | index | idx_age_name | idx_age_name | 773 | NULL | 3 | Using temporary; Using filesort | +----+-------------+----------+-------+---------------+--------------+---------+------+------+---------------------------------+ row in set (0.00 sec)
id当然为主键,其外就建立了一个联合索引(注意,联合索引的顺序很重要,很重要)
mysql> SHOW INDEX FROM test_person; +-------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | test_person | 0 | PRIMARY | 1 | id | A | 3 | NULL | NULL | | BTREE | | | | test_person | 1 | idx_age_birth | 1 | age | A | 3 | NULL | NULL | YES | BTREE | | | | test_person | 1 | idx_age_birth | 2 | birthday | A | 3 | NULL | NULL | YES | BTREE | | | +-------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 3 rows in set (0.00 sec)
例子一,注意order by 后面的以及extra下面的,在这里where后面的条件不变:
mysql> explain select * from test_person where age > 20 order by age; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ | 1 | SIMPLE | test_person | index | idx_age_birth | idx_age_birth | 11 | NULL | 3 | Using where; Using index | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ 1 row in set (0.01 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE age > 20 ORDER BY age,birthday; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ | 1 | SIMPLE | test_person | index | idx_age_birth | idx_age_birth | 11 | NULL | 3 | Using where; Using index | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE age > 20 ORDER BY birthday; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ | 1 | SIMPLE | test_person | index | idx_age_birth | idx_age_birth | 11 | NULL | 3 | Using where; Using index; Using filesort | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ 1 row in set (0.01 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE age > 20 ORDER BY birthday,age; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ | 1 | SIMPLE | test_person | index | idx_age_birth | idx_age_birth | 11 | NULL | 3 | Using where; Using index; Using filesort | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ 1 row in set (0.00 sec)
例子二,注意order by 后面的以及extra下面的,在这里where后面的条件不变:
mysql> EXPLAIN SELECT * FROM test_person WHERE birthday > '2012-12-12 00:00:00' ORDER BY age; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using where; Using index | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE birthday > '2012-12-12 00:00:00' ORDER BY age,birthday; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using where; Using index | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+--------------------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE birthday > '2012-12-12 00:00:00' ORDER BY birthday; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using where; Using index; Using filesort | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE birthday > '2012-12-12 00:00:00' ORDER BY birthday,age; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using where; Using index; Using filesort | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+------------------------------------------+ 1 row in set (0.00 sec)
例子三,这里得出的结论是,要不就得是同时升序,要不就得是同时降序啊,否则用不到索引:
mysql> EXPLAIN SELECT * FROM test_person ORDER BY age DESC; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using index | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person ORDER BY birthday DESC; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using index; Using filesort | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person ORDER BY age ASC, birthday DESC; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using index; Using filesort | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person ORDER BY age DESC, birthday DESC; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using index | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-------------+ 1 row in set (0.00 sec)
例子四:
mysql> EXPLAIN SELECT * FROM test_person ORDER BY id; +----+-------------+-------------+-------+---------------+---------+---------+------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------+---------+------+------+-------+ | 1 | SIMPLE | test_person | index | NULL | PRIMARY | 4 | NULL | 3 | NULL | +----+-------------+-------------+-------+---------------+---------+---------+------+------+-------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person ORDER BY id,birthday; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using index; Using filesort | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person ORDER BY id,age; +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ | 1 | SIMPLE | test_person | index | NULL | idx_age_birth | 11 | NULL | 3 | Using index; Using filesort | +----+-------------+-------------+-------+---------------+---------------+---------+------+------+-----------------------------+ 1 row in set (0.01 sec)
三、结论:
1)order by子句,尽量使用Index方式排序,在索引列上遵循索引的最佳左前缀原则。 复合(联合)索引形如 key (‘A1’,’A2’,’A3’ ),排序的思路一般是: 先按照A1来排序,A1相同,然后按照A2排序,以此类推,这样对于(A1),(A1,A2), (A1,A2,A3)的索引都是有效的,但是对于(A2,A3)这样的索引就无效了。尽量避免因索引字段的缺失 或 索引字段顺序的不同 引起的FileSort排序。 2)mysql一次查询只能使用一个索引。如果要对多个字段使用索引,建立复合索引。 ORDER BY 能使用索引最左前缀: - ORDER BY a - ORDER BY a,b - ORDER BY a,b,c - ORDER BY a DESC,b DESC,c DESC 如果 WHERE 使用索引的最左前缀为常量,则 ORDER BY能使用索引: - WHERE a = const ORDER BY b,c - WHERE a = const AND b = const ORDER BY c - WHERE a = const AND b > const ORDER BY b,c (请看下面的例子) 不能使用索引进行排序: - order by a asc, b desc, c desc (排序不一致嘛) - where g = const order by b,c (丢失a索引) - where a = const order by c (丢失b索引) - where a = const order by a,d (d不是索引的一部分) - where a in(...) order by b,c (对于排序来说,多个相等的条件也是范围查询) - 如果a,b分别建立了一个索引(不是普通索引,而是联合索引),对于这样的排序 order by a,b 是不会走索引 - 如果查询条件为函数,也无法使用索引
例子一:
mysql> SHOW INDEX FROM test_person; +-------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | test_person | 0 | PRIMARY | 1 | id | A | 3 | NULL | NULL | | BTREE | | | | test_person | 1 | idx_age_birth | 1 | age | A | 3 | NULL | NULL | YES | BTREE | | | | test_person | 1 | idx_age_birth | 2 | name | A | 3 | NULL | NULL | YES | BTREE | | | | test_person | 1 | idx_age_birth | 3 | birthday | A | 3 | NULL | NULL | YES | BTREE | | | +-------------+------------+---------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ rows in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE age = 1 AND name > 22 ORDER BY name,birthday; +----+-------------+-------------+------+---------------+---------------+---------+-------+------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+------+---------------+---------------+---------+-------+------+--------------------------+ | 1 | SIMPLE | test_person | ref | idx_age_birth | idx_age_birth | 5 | const | 1 | Using where; Using index | +----+-------------+-------------+------+---------------+---------------+---------+-------+------+--------------------------+ row in set (0.01 sec)
例子二:
mysql> SHOW INDEX FROM test_person; +-------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | +-------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ | test_person | 0 | PRIMARY | 1 | id | A | 3 | NULL | NULL | | BTREE | | | | test_person | 1 | idx_age | 1 | age | A | 3 | NULL | NULL | YES | BTREE | | | | test_person | 1 | idx_name | 1 | name | A | 3 | NULL | NULL | YES | BTREE | | | +-------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ rows in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person ORDER BY age,name; +----+-------------+-------------+------+---------------+------+---------+------+------+----------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+------+---------------+------+---------+------+------+----------------+ | 1 | SIMPLE | test_person | ALL | NULL | NULL | NULL | NULL | 3 | Using filesort | +----+-------------+-------------+------+---------------+------+---------+------+------+----------------+ row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE age = 22 ORDER BY age; +----+-------------+-------------+------+---------------+---------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+------+---------------+---------+---------+-------+------+-------+ | 1 | SIMPLE | test_person | ref | idx_age | idx_age | 5 | const | 1 | NULL | +----+-------------+-------------+------+---------------+---------+---------+-------+------+-------+ row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE age = 22 ORDER BY name; +----+-------------+-------------+------+---------------+---------+---------+-------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+------+---------------+---------+---------+-------+------+-----------------------------+ | 1 | SIMPLE | test_person | ref | idx_age | idx_age | 5 | const | 1 | Using where; Using filesort | +----+-------------+-------------+------+---------------+---------+---------+-------+------+-----------------------------+ row in set (0.01 sec) mysql> EXPLAIN SELECT * FROM test_person WHERE birthday = NOW() ORDER BY name; +----+-------------+-------------+------+---------------+------+---------+------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------------+------+---------------+------+---------+------+------+-----------------------------+ | 1 | SIMPLE | test_person | ALL | NULL | NULL | NULL | NULL | 3 | Using where; Using filesort | +----+-------------+-------------+------+---------------+------+---------+------+------+-----------------------------+ row in set (0.01 sec)
group by与order by的索引优化基本一样,group by实质是先排序后分组,也就是分组之前必排序,遵照索引的最佳左前缀原则可以大大提高group by的效率。