mysql中order by优化的那些事儿

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

为了测试方便和直观,我们需要先创建一张测试表并插入一些数据:

 
 
  1. CREATE TABLE `shop` ( 
  2.   `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '记录ID', 
  3.   `shop_id` int(11) NOT NULL COMMENT '商店ID', 
  4.   `goods_id` int(11) NOT NULL COMMENT '物品ID', 
  5.   `pay_type` tinyint(1) NOT NULL COMMENT '支付方式', 
  6.   `price` decimal(10,2) NOT NULL COMMENT '物品价格', 
  7.   `comment` varchar(200) NOT NULL COMMENT '备注', 
  8.   PRIMARY KEY (`id`), 
  9.   UNIQUE KEY `shop_id` (`shop_id`,`goods_id`), 
  10.   KEY `price` (`price`), 
  11.   KEY `pay_type` (`pay_type`) 
  12. ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='商店物品表' 

插入几行数据:

 
 
  1. INSERT INTO `shop` (`id`, `shop_id`, `goods_id`, `pay_type`, `price`, `comment`) VALUES 
  2. (1, 1, 1, 0, '1.00', ''), 
  3. (2, 2, 1, 0, '24.00', ''), 
  4. (3, 2, 3, 1, '5.99', ''), 
  5. (4, 3, 1, 0, '1.99', ''), 
  6. (5, 3, 2, 1, '81.00', ''), 
  7. (6, 4, 2, 0, '15.00', ''), 
  8. (7, 4, 3, 0, '22.00', ''); 

好了。现在我们可以开始我们的学习了。

对照一下官方手册:http://dev.mysql.com/doc/refman/5.5/en/order-by-optimization.html

手册上说,如下的四种情况mysql是会作优化的:

 
 
  1. SELECT * FROM t1 ORDER BY key_part1,key_part2,... ;  
  2. SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2;  
  3. SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC; 
  4. SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC; 

真的是这样么?按手册上的说法,如果explain的extra中出现了Using filesort则是没有用到排序优化。来吧,让我们挨个测试一下:

可优化的第一种情况

 
 
  1. SELECT * FROM t1 ORDER BY key_part1,key_part2,...; 

指的是使用联合索引中的各个字段进行排序:

 
 
  1. mysql> explain select * from shop order by shop_id,goods_id; 
  2. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          | 
  4. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  5. |  1 | SIMPLE      | shop  | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using filesort | 
  6. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  7. 1 row in set (0.00 sec) 

当我们检索所有记录时可以看到,索引优化是无效的。如果改成如下的查询就可以应用上索引优化:

 
 
  1. mysql> explain select id,shop_id,goods_id from shop order by shop_id,goods_id; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 | Using index | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  7. 1 row in set (0.00 sec) 

这里的三个字段是在索引树中存放的,因此可以直接从索引树检索出来,不用去检索行,所以extra显示的是Using index不会出现Using filesort。而一旦我们加上了除主键之外的非排序字段,索引优化就失效了。

另外,还可以强制指定索引,这样也可以应用上索引优化:

 
 
  1. mysql> explain select * from shop force index(shop_id) order by shop_id,goods_id; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 |       | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  7. 1 row in set (0.03 sec) 

可优化的第二种情况

 
 
  1. SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2; 

这种情况指的是联合索引中的一部分指定了常量去检索,排序则使用了索引的另一部分。

 
 
  1. mysql> explain select * from shop where shop_id=2 order by goods_id; 
  2. +----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+ 
  3. | id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       | 
  4. +----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+ 
  5. |  1 | SIMPLE      | shop  | ref  | shop_id       | shop_id | 4       | const |    2 | Using where | 
  6. +----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+ 
  7. 1 row in set (0.00 sec) 

的确,该情况索引优化是有效的。

可优化的第三种情况

 
 
  1. SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;  

这种情况与第一种情况类似,仅仅是排序方向变更了,不出意外的话仍然不会有优化:

 
 
  1. mysql> explain select * from shop order by shop_id desc,goods_id desc; 
  2. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          | 
  4. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  5. |  1 | SIMPLE      | shop  | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using filesort | 
  6. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  7. 1 row in set (0.00 sec) 

果然,没有排序优化。同样,如果只检索主键和排序字段,排序优化有效:

 
 
  1. mysql> explain select id,shop_id,goods_id from shop order by shop_id desc,goods_id desc; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 | Using index | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  7. 1 row in set (0.00 sec) 

如果强制指定索引呢?

 
 
  1. mysql> explain select * from shop force index(shop_id) order by shop_id desc,goods_id desc; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 |       | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  7. 1 row in set (0.00 sec) 

可见也是有效的。

可优化的第四种情况

 
 
  1. SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC; 

以索引的一部分为条件并且是常量,排序按索引的各字段倒排时,这种情况排序优化有效:

 
 
  1. mysql> explain select * from shop where shop_id=2 order by shop_id desc,goods_id desc; 
  2. +----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+ 
  3. | id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       | 
  4. +----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+ 
  5. |  1 | SIMPLE      | shop  | ref  | shop_id       | shop_id | 4       | const |    2 | Using where | 
  6. +----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+ 
  7. 1 row in set (0.00 sec) 

对于何时排序优化有效,官方手册上是这样说的:

The index can also be used even if the ORDER BY does not match the index exactly, as long as all of the unused portions of the index and all the extra ORDER BY columns are constants in the WHERE clause.

翻译:

即使ORDER BY不精确匹配索引也能使用索引,只要WHERE子句中的所有未使用的索引部分所有额外的ORDER BY列为常数就行

这句话中有两个细节,如上面标蓝的部分,下面举个例子来说明一下:

比如情况二,

 
 
  1. SELECT * FROM t1 WHERE key_part1=constant ORDER BY key_part2; 

ORDER BY子句是key_part2,并未精确的匹配索引(精确匹配就应当是key_part1,key_part2),但是where子句中使用了索引的一部分(key_part1)并且为常数,而对于ORDER BY来说,key_part1就是额外的,它不出现在ORDER BY子句中便却是索引的一部分,这样,排序就可以用到索引来优化了。

------------------------------- 这里需要一根分隔线 -------------------------------

手册上还介绍了几种无法应用排序优化的情况,我们来看一下:

无法优化的情况1

 
 
  1. SELECT * FROM t1 ORDER BY key1, key2; 

这种情况是当排序时指定了两个索引时:

 
 
  1. mysql> explain select * from shop order by id,price; 
  2. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          | 
  4. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  5. |  1 | SIMPLE      | shop  | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using filesort | 
  6. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  7. 1 row in set (0.00 sec) 

本例中用到了两个索引,其中id还是主键,但这也无助于排序优化。这种情况下,即使指定了检索结果集,也无法避免Using filesort。

无法优化的情况2

 
 
  1. SELECT * FROM t1 WHERE key2=constant ORDER BY key_part2; 

当查询条件使用了别的索引,且值为常量,但排序字段是另一个联合索引的非连续部分时:

 
 
  1. mysql> explain select * from shop where price=15 order by goods_id;  
  2. +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------+ 
  3. | id | select_type | table | type | possible_keys | key   | key_len | ref   | rows | Extra                       | 
  4. +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------+ 
  5. |  1 | SIMPLE      | shop  | ref  | price         | price | 5       | const |    1 | Using where; Using filesort | 
  6. +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------------+ 
  7. 1 row in set (0.00 sec)

无法优化的情况3

 
 
  1. SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC; 

混用两种排序方向时,这种情况如果指定了结果集为主键或联合索引字段,也无法避免Using filesort:

 
 
  1. mysql> explain select * from shop order by shop_id asc,goods_id desc;  
  2. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          | 
  4. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  5. |  1 | SIMPLE      | shop  | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using filesort | 
  6. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  7. 1 row in set (0.00 sec) 

无法优化的情况4

 
 
  1. SELECT * FROM t1 WHERE key2=constant ORDER BY key1; 

这种情况指的是查询时按索引2,而排序时按索引1,真的是不能优化么?

 
 
  1. mysql> explain select * from shop where pay_type=1 order by price;  
  2. +----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------------+ 
  3. | id | select_type | table | type | possible_keys | key      | key_len | ref   | rows | Extra                       | 
  4. +----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------------+ 
  5. |  1 | SIMPLE      | shop  | ref  | pay_type      | pay_type | 1       | const |    2 | Using where; Using filesort | 
  6. +----+-------------+-------+------+---------------+----------+---------+-------+------+-----------------------------+ 
  7. 1 row in set (0.00 sec) 

当我们指定了pay_type为1来检索行,并按price来排序时,发现的确不能优化排序。如果按id来排序呢?

 
 
  1. mysql> explain select * from shop where pay_type=1 order by id;  
  2. +----+-------------+-------+------+---------------+----------+---------+-------+------+-------------+ 
  3. | id | select_type | table | type | possible_keys | key      | key_len | ref   | rows | Extra       | 
  4. +----+-------------+-------+------+---------------+----------+---------+-------+------+-------------+ 
  5. |  1 | SIMPLE      | shop  | ref  | pay_type      | pay_type | 1       | const |    2 | Using where | 
  6. +----+-------------+-------+------+---------------+----------+---------+-------+------+-------------+ 
  7. 1 row in set (0.00 sec) 

很惊奇的发现,排序被优化了。

无法优化的情况5

 
 
  1. SELECT * FROM t1 ORDER BY ABS(key); 
  2. SELECT * FROM t1 ORDER BY -key; 

这种情况指的是按表达式来排序,为了更直观的看出区别,我们作了三种情况:

1)用主键排序

 
 
  1. mysql> explain select * from shop order by id;  
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | PRIMARY | 4       | NULL |    7 |       | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  7. 1 row in set (0.00 sec) 

2)ABS表达式

 
 
  1. mysql> explain select * from shop order by ABS(id);  
  2. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          | 
  4. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  5. |  1 | SIMPLE      | shop  | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using filesort | 
  6. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  7. 1 row in set (0.00 sec) 

3)负号

 
 
  1. mysql> explain select * from shop order by -id;  
  2. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  3. | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          | 
  4. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  5. |  1 | SIMPLE      | shop  | ALL  | NULL          | NULL | NULL    | NULL |    7 | Using filesort | 
  6. +----+-------------+-------+------+---------------+------+---------+------+------+----------------+ 
  7. 1 row in set (0.28 sec) 

可见,用表达式的情况的确不会排序优化。

无法优化的情况6

官方的翻译:当联接了多张表,并且ORDER BY中的列并不是全部来自第1个用于搜索行的非常量表.(这是EXPLAIN输出中的没有使用const联接类型的第1个表)。

分析一下标蓝的部分:
列来自表 -> 
列不是来自表 -> 
列不是全部来自表 -> 
列不是全部来自非常量表 -> 
列不是全部来自第一个用于搜索行的非常量表。

要测试这种情况,我们需要新增一张表:

 
 
  1. CREATE TABLE `pay_type` ( 
  2.   `type_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', 
  3.   `rate` decimal(6,2) NOT NULL COMMENT '费率', 
  4.   `name` varchar(20) NOT NULL COMMENT '名称', 
  5.   PRIMARY KEY (`type_id`) 
  6. ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='支付方式表' 

插入几条记录:

 
 
  1. INSERT INTO `pay_type` (`type_id`, `rate`, `name`) VALUES 
  2. (1, '0.01', '手机'), 
  3. (2, '0.02', '网银'), 
  4. (3, '0.00', '货到付款'); 

我们测试一下:

 
 
  1. mysql> explain select * from shop a left join pay_type b on a.pay_type=b.type_id where a.id>2 order by a.goods_id,b.type_id; 
  2. +----+-------------+-------+--------+---------------+---------+---------+-----------------+------+----------------------------------------------+ 
  3. | id | select_type | table | type   | possible_keys | key     | key_len | ref             | rows | Extra                                        | 
  4. +----+-------------+-------+--------+---------------+---------+---------+-----------------+------+----------------------------------------------+ 
  5. |  1 | SIMPLE      | a     | range  | PRIMARY       | PRIMARY | 4       | NULL            |    5 | Using where; Using temporary; Using filesort | 
  6. |  1 | SIMPLE      | b     | eq_ref | PRIMARY       | PRIMARY | 4       | test.a.pay_type |    1 |                                              | 
  7. +----+-------------+-------+--------+---------------+---------+---------+-----------------+------+----------------------------------------------+ 
  8. 2 rows in set (0.28 sec) 

a表是一个非常量表,并且是执行计划中的第一个,这满足上面所说的表类型。
order by中的列来自于两张表,所以不是全部来自于a表。
对于这样的情况,的确不能做排序优化。

无法优化的情况7

有不同的ORDER BY和GROUP BY表达式。

 
 
  1. mysql> explain select shop_id, max(price) max_price from shop group by shop_id order by max_price desc; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+---------------------------------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                           | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+---------------------------------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 | Using temporary; Using filesort | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+---------------------------------+ 
  7. 1 row in set (0.04 sec) 

当我们按shop_id进行分组后,想按最高价的商品倒排时,可以看到没有排序优化。如果排序的字段与分组的字段一致,都是shop_id,排序优化就生效了。

 
 
  1. mysql> explain select shop_id, max(price) max_price from shop group by shop_id order by shop_id desc; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 |       | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------+ 
  7. 1 row in set (0.01 sec) 

无法优化的情况8

如果指定了索引长度,且索引长度小于字段长度时,不能进行排序优化。

我们需要修改一下上面创建的pay_type表,加一个索引,索引长度是1:

 
 
  1. ALTER TABLE `test`.`pay_type` ADD INDEX `name` ( `name` ( 1 ) )  

然后测试:

 
 
  1. mysql> explain select * from pay_type force index(name) order by name; 
  2. +----+-------------+----------+------+---------------+------+---------+------+------+----------------+ 
  3. | id | select_type | table    | type | possible_keys | key  | key_len | ref  | rows | Extra          | 
  4. +----+-------------+----------+------+---------------+------+---------+------+------+----------------+ 
  5. |  1 | SIMPLE      | pay_type | ALL  | NULL          | NULL | NULL    | NULL |    3 | Using filesort | 
  6. +----+-------------+----------+------+---------------+------+---------+------+------+----------------+ 
  7. 1 row in set (0.00 sec) 

的确,没有排序优化。如果不指定name的长度呢,先修改一下索引:

 
 
  1. ALTER TABLE `test`.`pay_type` DROP INDEX `name` , 
  2. ADD INDEX `name` ( `name` )  

然后执行:

 
 
  1. mysql> explain select * from pay_type force index(name) order by name; 
  2. +----+-------------+----------+-------+---------------+------+---------+------+------+-------+ 
  3. | id | select_type | table    | type  | possible_keys | key  | key_len | ref  | rows | Extra | 
  4. +----+-------------+----------+-------+---------------+------+---------+------+------+-------+ 
  5. |  1 | SIMPLE      | pay_type | index | NULL          | name | 62      | NULL |    3 |       | 
  6. +----+-------------+----------+-------+---------------+------+---------+------+------+-------+ 
  7. 1 row in set (0.00 sec) 

这样排序优化是有效的。

无法优化的情况9

使用的表索引的类型不能按顺序保存行。例如,对于HEAP表的HASH索引情况即如此。有不同的ORDER BY和GROUP BY表达式

要测试这种情况,我们得新建一张表:

 
 
  1. CREATE TABLE `heap_test` ( 
  2.   `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID', 
  3.   `name` varchar(20) NOT NULL COMMENT '名称', 
  4.   PRIMARY KEY (`id`), 
  5.   KEY `name` (`name`) 
  6. ENGINE=MEMORY AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='测试heap表' 

插入几条记录:

 
 
  1. INSERT INTO `heap_test` (`id`, `name`) VALUES 
  2. (1, '张三'), 
  3. (2, '李四'); 

测试一下:

 
 
  1. mysql> explain select * from heap_test force index(name) order by name; 
  2. +----+-------------+-----------+------+---------------+------+---------+------+------+----------------+ 
  3. | id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows | Extra          | 
  4. +----+-------------+-----------+------+---------------+------+---------+------+------+----------------+ 
  5. |  1 | SIMPLE      | heap_test | ALL  | NULL          | NULL | NULL    | NULL |    2 | Using filesort | 
  6. +----+-------------+-----------+------+---------------+------+---------+------+------+----------------+ 
  7. 1 row in set (0.00 sec) 

的确排序优化无效。

除了以上的情况,还有几个要注意的地方。

注意点1

字段别名对排序的影响:

 
 
  1. mysql> explain select abs(shop_id) shop_id from shop force index(shop_id) order by shop_id; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                       | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 | Using index; Using filesort | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+-----------------------------+ 
  7. 1 row in set (0.00 sec) 

这个例子中我们对shop_id取绝对值并给了一个别名shop_id,不幸的是,这个表中的确有一个字段叫shop_id,此时按shop_id排序,用到的是别名而不是字段,即使强制使用了shop_id索引也无效。对于这种情况,换一个别名就可以解决:

 
 
  1. mysql> explain select abs(shop_id) shop_new_id from shop force index(shop_id) order by shop_id; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra       | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 | Using index | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+ 
  7. 1 row in set (0.00 sec) 

注意点2

group by默认会对字段排序,跟你显示的按分组字段order by一样,写不写出来都一样,没有性能损失。如果想避免group by的排序开销,可以强制指定取消排序,先看一下不取消的情况:

 
 
  1. mysql> explain select goods_id,count(1) from shop force index(shop_id) group by goods_id; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+----------------------------------------------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                                        | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+----------------------------------------------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 | Using index; Using temporary; Using filesort | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+----------------------------------------------+ 
  7. 1 row in set (0.00 sec) 

再看一下取消的情况:

 
 
  1. mysql> explain select goods_id,count(1) from shop force index(shop_id) group by goods_id order by null; 
  2. +----+-------------+-------+-------+---------------+---------+---------+------+------+------------------------------+ 
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows | Extra                        | 
  4. +----+-------------+-------+-------+---------------+---------+---------+------+------+------------------------------+ 
  5. |  1 | SIMPLE      | shop  | index | NULL          | shop_id | 8       | NULL |    7 | Using index; Using temporary | 
  6. +----+-------------+-------+-------+---------------+---------+---------+------+------+------------------------------+ 
  7. 1 row in set (0.00 sec) 

此时已经没有了Using filesort。

注意点3

如果排序不可避免,可以用下面的办法加速:

  • 增加sort_buffer_size变量的大小。
  • 增加read_rnd_buffer_size变量的大小。
  • 更改tmpdir指向具有大量空闲空间的专用文件系统。









本文转自 ustb80 51CTO博客,原文链接:http://blog.51cto.com/ustb80/1073352,如需转载请自行联系原作者
相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
9天前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
72 9
|
1月前
|
SQL 关系型数据库 MySQL
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
MySQL慢查询优化、索引优化,是必知必备,大厂面试高频,本文深入详解,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验分享。
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
|
13天前
|
缓存 关系型数据库 MySQL
MySQL 索引优化以及慢查询优化
通过本文的介绍,希望您能够深入理解MySQL索引优化和慢查询优化的方法,并在实际应用中灵活运用这些技术,提升数据库的整体性能。
52 18
|
12天前
|
缓存 关系型数据库 MySQL
MySQL 索引优化以及慢查询优化
通过本文的介绍,希望您能够深入理解MySQL索引优化和慢查询优化的方法,并在实际应用中灵活运用这些技术,提升数据库的整体性能。
18 7
|
11天前
|
缓存 关系型数据库 MySQL
MySQL 索引优化与慢查询优化:原理与实践
通过本文的介绍,希望您能够深入理解MySQL索引优化与慢查询优化的原理和实践方法,并在实际项目中灵活运用这些技术,提升数据库的整体性能。
41 5
|
1月前
|
SQL 关系型数据库 MySQL
MySQL慢查询优化、索引优化、以及表等优化详解
本文详细介绍了MySQL优化方案,包括索引优化、SQL慢查询优化和数据库表优化,帮助提升数据库性能。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
MySQL慢查询优化、索引优化、以及表等优化详解
|
1月前
|
关系型数据库 MySQL Java
MySQL索引优化与Java应用实践
【11月更文挑战第25天】在大数据量和高并发的业务场景下,MySQL数据库的索引优化是提升查询性能的关键。本文将深入探讨MySQL索引的多种类型、优化策略及其在Java应用中的实践,通过历史背景、业务场景、底层原理的介绍,并结合Java示例代码,帮助Java架构师更好地理解并应用这些技术。
32 2
|
3天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
13 3
|
3天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
18 3
|
3天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE 'log_%';`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
22 2