SQL optimization case a

 Once developed and asked me why this statement is running so slow, I hope to be able to look at a solution. The following statements can be reduced to this:

select ftime , memberid from   f_zhenai_dish_ip_d where ftime >= '20190918' and ftime <= '20190919' group by ftime, memberid order by ftime desc limit 50 offset 0;

Of course, is to look at the execution plan

+----+-------------+--------------------+------------+-------+--------------------------------+-------------+---------+------+----------+----------+--------------------------------------------------------+

| id | select_type | table              | partitions | type  | possible_keys                  | key         | key_len | ref  | rows     | filtered | Extra                                                  |

+----+-------------+--------------------+------------+-------+--------------------------------+-------------+---------+------+----------+----------+--------------------------------------------------------+

|  1 | SIMPLE      | f_zhenai_dish_ip_d | NULL       | range | index_ftime | index_ftime | 9       | NULL | 17820877 |   100.00 | Using index condition; Using temporary; Using filesort |

+----+-------------+--------------------+------------+-------+--------------------------------+-------------+---------+------+----------+----------+--------------------------------------------------------+

Seen from the execution plan, the use of the sql index on ftime columns, but the use of temporary tables and sort, which is the main reason for this sql so slow. How to avoid ordering it, this column is not memeberid sort resulting from it? So we try to build a joint index (ftime, memberid). Look again at what the implementation plan.

+----+-------------+--------------------+------------+-------+--------------------------------+-------------+---------+------+----------+----------+--------------------------------------------------------+

| id | select_type | table              | partitions | type  | possible_keys                  | key         | key_len | ref  | rows     | filtered | Extra                                                  |

+----+-------------+--------------------+------------+-------+--------------------------------+-------------+---------+------+----------+----------+--------------------------------------------------------+

|  1 | SIMPLE      | f_zhenai_dish_ip_d | NULL       | range | index_ftime,idx_ftime_memberid | index_ftime | 9       | NULL | 17820877 |   100.00 | Using index condition; Using temporary; Using filesort |

+----+-------------+--------------------+------------+-------+--------------------------------+-------------+---------+------+----------+----------+--------------------------------------------------------+

What? Not only this new index. If that force it to use the new joint index what will happen?

mysql> explain select   ftime,   memberid from   f_zhenai_dish_ip_d force index (idx_ftime_memberid) where   ftime >= '20190918'   and ftime <= '20190919' group by   ftime,   memberid order by   ftime desc limit   50 offset 0;

+----+-------------+--------------------+------------+-------+--------------------+--------------------+---------+------+----------+----------+--------------------------------------------------------+

| id | select_type | table              | partitions | type  | possible_keys      | key                | key_len | ref  | rows     | filtered | Extra                                                  |

+----+-------------+--------------------+------------+-------+--------------------+--------------------+---------+------+----------+----------+--------------------------------------------------------+

|  1 | SIMPLE      | f_zhenai_dish_ip_d | NULL       | range | idx_ftime_memberid | idx_ftime_memberid | 9       | NULL | 17820877 |   100.00 | Using index condition; Using temporary; Using filesort |

+----+-------------+--------------------+------------+-------+--------------------+--------------------+---------+------+----------+----------+--------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)

Even with this joint index, then any need to create a temporary table and sort, which is more strange.

Later I found order by the time specified in descending order, I try to delete desc look at the execution plan.

mysql> explain select   ftime,   memberid from   f_zhenai_dish_ip_d where   ftime >= '20190918'   and ftime <= '20190919' group by   ftime,   memberid order by   ftime limit   50 offset 0;

+----+-------------+--------------------+------------+-------+--------------------------------+--------------------+---------+------+----------+----------+-----------------------+

| id | select_type | table              | partitions | type  | possible_keys                  | key                | key_len | ref  | rows     | filtered | Extra                 |

+----+-------------+--------------------+------------+-------+--------------------------------+--------------------+---------+------+----------+----------+-----------------------+

|  1 | SIMPLE      | f_zhenai_dish_ip_d | NULL       | range | index_ftime,idx_ftime_memberid | idx_ftime_memberid | 9       | NULL | 17820877 |   100.00 | Using index condition |

+----+-------------+--------------------+------------+-------+--------------------------------+--------------------+---------+------+----------+----------+-----------------------+

1 row in set, 1 warning (0.01 sec)

??? 竟然是一个desc导致的问题。

于是我去问开发,能不能把order by 排序规则改成asc,开发说不能,这个要按照时间的顺序排列,时间最早的要排在最前面。

最后sql改成了这个样子:

select ftime , memberid from f_zhenai_dish_ip_d where ftime >= '20190918' and ftime <= '20190919' group by ftime, memberid order by ftime desc memberid desc limit 50 offset 0;

 

所以本文一共有三个问题

第一个问题是,在还没有加索引之前,这条语句这么慢是不是memberid这列没有索引导致的?

是的。因为group by ftime,memberid的时候,memberid也要排序,而索引上并没有这列,因此无法通过索引来优化排序。

第二个问题是,为什么我加了联合索引它却没有使用这个索引?

因为desc导致的

第三个问题,为什么desc就慢,而asc就快?为什么加了一个desc排序的列也快呢?

对于索引(ftime,memberid),索引上的数据首先按照ftime从小到大排列,对于ftime值相同的再按照memberid从小到大排列。所以这个索引可以看作是经过 order by ftime asc,memberid asc 排序过了的。再来看看我们的sql, group by ftime, memberid order by ftime desc ,这部分看成group by ftime desc memberid asc 。这跟我们的索引顺序 ftime asc,memberid asc 并不一致,所以要排序。

那如果是 group by ftime,   memberid order by   ftime desc,memberid desc 呢?这个子句可以看成 group by ftime desc memberid desc 。虽然索引是 ftime asc,member asc 的顺序,但如果从后往前扫描就不需要再排序了。

 

Guess you like

Origin www.cnblogs.com/ayard/p/11568502.html