全部博文(389)
分类: Mysql/postgreSQL
2015-04-18 17:36:01
Mysql Order By列索引的影响
Order By(以下简称OB)对排序的影响,OB列上有索引,如果不包含 where条件,类似于以下查询:
表结构
CREATE TABLE `snapshot` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`snap_id` int(11) DEFAULT NULL,
`name` varchar(500) DEFAULT NULL,
`value` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `snap_id_ix` (`snap_id`),
KEY `name_ix` (`name`(255))
) ENGINE=InnoDB
mysql> select *
-> from snapshot
-> order by snap_id desc;
该sql可以有两种执行计划,第一种方法是直接读取表记录,然后根据OB列去排序。
第二种方法是先扫描OB上的索引,由于索引本身就是排好序的,因此根据索引的顺序
再读出表的记录即可,省去排序的过程.
我们可以看出第一种方法直接读取表记录就可以了.第二种方法需要先读取索引,然后根据索引去读取表记录,
io会变得很随机,因此这种方法会成本比较高,所以优化器会选择第一种执行执行划。
来看第一种执行方法的情况
mysql> explain select *
-> from snapshot
-> order by snap_id desc;
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | snapshot | ALL | NULL | NULL | NULL | NULL | 6415 | Using filesort |
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)
mysql> show status like '%cost%';
+-----------------+-------------+
| Variable_name | Value |
+-----------------+-------------+
| Last_query_cost | 7721.999000 |
+-----------------+-------------+
1 row in set (0.00 sec)
执行的方式使用了全表扫描,extra中提示信息使用了排序,计划的成本是7721,这种情况下可以看出OB列上是否
有索引对排序没有什么影响.
第二种执行方法的情况,通过force index提示,强制mysql使用索引
mysql> explain select *
-> from snapshot force index (snap_id)
-> order by snap_id desc;
+----+-------------+----------+-------+---------------+------------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+------------+---------+------+------+-------+
| 1 | SIMPLE | snapshot | index | NULL | snap_id_ix | 5 | NULL | 6415 | NULL |
+----+-------------+----------+-------+---------------+------------+---------+------+------+-------+
1 row in set (0.00 sec)
mysql> show status like '%cost%';
+-----------------+--------------+
| Variable_name | Value |
+-----------------+--------------+
| Last_query_cost | 14113.999000 |
+-----------------+--------------+
1 row in set (0.00 sec)
执行使用索引,没有排序操作,但是成本变得高出将近快一倍了,所以mysql为我们选择了第一种方法.
第三种情况是limit操作带来的影响,来看两种limit操作的结果
mysql> explain
-> select *
-> from snapshot
-> order by snap_id desc
-> limit 0,100;
+----+-------------+----------+-------+---------------+------------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+------------+---------+------+------+-------+
| 1 | SIMPLE | snapshot | index | NULL | snap_id_ix | 5 | NULL | 100 | NULL |
+----+-------------+----------+-------+---------------+------------+---------+------+------+-------+
1 row in set (0.00 sec)
mysql> explain
-> select *
-> from snapshot
-> order by snap_id desc
-> limit 100,200
-> ;
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE | snapshot | ALL | NULL | NULL | NULL | NULL | 6415 | Using filesort |
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
1 row in set (0.00 sec)
第二个查询由于是取不同段的数据,但是之前的索引也要扫描,只是被放弃了,虽然也是取100行数据,但还是
走的全表扫描,这种情况也只能查出主键之类的,然后再去优化了.
对于有limit之类的查询,可以看出OB列上有索引对查询计划有很大影响。现实中的查询可能更加复杂,比如where列,
连接等再需要针对具体情况再进行分析了.