一个mysql索引顺序优化的案例

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个mysql索引顺序优化的案例相关的知识,希望对你有一定的参考价值。

sql:

select imsi from g_businessimsi where status=‘0‘ and channel=‘xiaomi‘ and expirdate<‘201605300101‘ order by lastmodifytime asc limit 1;


这么一个需要频繁执行的sql,感觉性能不太理想,g_businessimsi表字段如下:
mysql> show index from g_businessimsi;
+----------------+------------+-----------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table          | Non_unique | Key_name        | Seq_in_index | Column_name    | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------------+------------+-----------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| g_businessimsi |          0 | PRIMARY         |            1 | imsi           | A         |       35559 |     NULL | NULL   |      | BTREE      |         |               |
| g_businessimsi |          0 | msisdn_index    |            1 | msisdn         | A         |       35559 |     NULL | NULL   |      | BTREE      |         |               |
| g_businessimsi |          1 | Index_cloudimsi |            1 | cloudimsi      | A         |           2 |     NULL | NULL   | YES  | BTREE      |         |               |
| g_businessimsi |          1 | index_c         |            1 | channel        | A         |           4 |     NULL | NULL   | YES  | BTREE      |         |               |
| g_businessimsi |          1 | index_c         |            2 | status         | A         |           4 |     NULL | NULL   |      | BTREE      |         |               |
| g_businessimsi |          1 | index_c         |            3 | expirdate      | A         |           4 |     NULL | NULL   | YES  | BTREE      |         |               |
| g_businessimsi |          1 | index_c         |            4 | lastmodifytime | A         |        8889 |     NULL | NULL   | YES  | BTREE      |         |               |
+----------------+------------+-----------------+--------------+----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
7 rows in set (0.00 sec)


1、执行计划如下

mysql> explain select imsi from g_businessimsi where status=‘0‘ and channel=‘xiaomi‘ and expirdate<‘201605300101‘ \
    -> order by lastmodifytime asc limit 1;
+----+-------------+----------------+-------+---------------+---------+---------+------+-------+------------------------------------------+
| id | select_type | table          | type  | possible_keys | key     | key_len | ref  | rows  | Extra                                    |
+----+-------------+----------------+-------+---------------+---------+---------+------+-------+------------------------------------------+
|  1 | SIMPLE      | g_businessimsi | range | index_c       | index_c | 218     | NULL | 17779 | Using where; Using index; Using filesort |
+----+-------------+----------------+-------+---------------+---------+---------+------+-------+------------------------------------------+
1 row in set (0.00 sec)


2、看看profile

mysql> show profile for query 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000108 |
| checking permissions | 0.000015 |
| Opening tables       | 0.000035 |
| System lock          | 0.000015 |
| init                 | 0.000033 |
| optimizing           | 0.000024 |
| statistics           | 0.000128 |
| preparing            | 0.000026 |
| executing            | 0.000004 |
| Sorting result       | 0.067427 |
| Sending data         | 0.000156 |
| end                  | 0.000012 |
| query end            | 0.000007 |
| closing tables       | 0.000009 |
| freeing items        | 0.000188 |
| logging slow query   | 0.000004 |
| cleaning up          | 0.000004 |
+----------------------+----------+
17 rows in set (0.00 sec)



可以看到,sorting result花费了很多时间,上面也使用了filesort。


调整下索引顺序,将顺序调整为:lastmodifytime,expirdate,status,channel

再看执行计划:

mysql> explain select imsi from g_businessimsi where status=‘0‘ and channel=‘xiaomi‘ and expirdate<‘201605300101‘ \
    -> order by lastmodifytime asc limit 1;
+----+-------------+----------------+-------+---------------+---------+---------+------+------+--------------------------+
| id | select_type | table          | type  | possible_keys | key     | key_len | ref  | rows | Extra                    |
+----+-------------+----------------+-------+---------------+---------+---------+------+------+--------------------------+
|  1 | SIMPLE      | g_businessimsi | index | NULL          | index_c | 227     | NULL |    1 | Using where; Using index |
+----+-------------+----------------+-------+---------------+---------+---------+------+------+--------------------------+
1 row in set (0.00 sec)


没有filesort了,


mysql> show profile for query 6;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000144 |
| checking permissions | 0.000010 |
| Opening tables       | 0.000047 |
| System lock          | 0.000012 |
| init                 | 0.000039 |
| optimizing           | 0.000030 |
| statistics           | 0.000024 |
| preparing            | 0.000019 |
| executing            | 0.000007 |
| Sorting result       | 0.000006 |
| Sending data         | 0.000104 |
| end                  | 0.000007 |
| query end            | 0.000009 |
| closing tables       | 0.000008 |
| freeing items        | 0.000022 |
| logging slow query   | 0.000002 |
| cleaning up          | 0.000003 |
+----------------------+----------+
17 rows in set (0.00 sec)


时间主要用于sending data,比较正常了。


到这里,不用多说,这个sql的执行时间有了显著缩短,在使用覆盖索引(covering index)的时候,有很多注意事项,写sql的时候不可太随意,否则性能差异巨大。


ps:Extra里面出现using index表示此次sql执行用的是覆盖索引。什么是覆盖索引?就是查询的时候,只使用二级索引就可以搞定,不需要回到主索引去获取其它列的数据。

本文出自 “记忆碎片” 博客,谢绝转载!

以上是关于一个mysql索引顺序优化的案例的主要内容,如果未能解决你的问题,请参考以下文章

Mysql学习笔记(全)

Mysql语句及优化

MySQL索引优化(索引单表优化案例)

MySQL索引优化(索引三表优化案例)

mysql索引优化

【Mysql】查询优化——减少回表操作