面经-一条sql执行很慢,可能是因为什么? 怎么优化?

105 阅读5分钟

在应用的的开发过程中,由于初期数据量小,开发人员写 SQL 语句时更重视功能上的实现,但是当应用系统正式上线后,随着生产数据量的急剧增长,很多 SQL 语句开始逐渐显露出性能问题,对生产的影响也越来越大,此时这些有问题的 SQL 语句就成为整个系统性能的瓶颈,因此我们必须要对它们进行优化。

  1. 可以使用show processlist命令查看当前MySQL在进行的线程,包括线程的状态、是否锁表等,可以实时地查看 SQL 的执行情况,定位低效率sql,同时对一些锁表操作进行优化。

  2. 然后再用explain分析执行计划:通过该命令可以查看SQL在真正执行时所需要经历的一系列过程,通过执行结果可以看出一条复杂的SQL查找顺序、是否有通过索引查询等信息。执行计划命令所带的SQL并不会真正执行,所以不会担心占用系统资源,用于对SQL进行分析优化非常有用。。(是否索引失效,用到索引没,用了哪些)

mysql> select * from post;
+----+------------------+--------+---------------+-------------------+--------------+--------+---------------------+---------------------+
| id | post_id          | title  | content       | author_id         | community_id | status | create_time         | update_time         |
+----+------------------+--------+---------------+-------------------+--------------+--------+---------------------+---------------------+
|  1 |  959630985400320 | 真牛逼 | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-03 23:33:13 | 2022-07-03 23:33:13 |
|  2 | 1127631193903104 | 你好   | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-04 10:40:48 | 2022-07-04 10:40:48 |
|  3 | 1149343172136960 | 你好   | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-04 12:07:04 | 2022-07-04 12:07:04 |
|  4 | 1149745036791808 | 你好   | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-04 12:08:40 | 2022-07-04 12:08:40 |
|  5 | 1149992383287296 | 你好   | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-04 12:09:39 | 2022-07-04 12:09:39 |
|  6 | 1153257435041792 | 111    | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-04 12:22:38 | 2022-07-04 12:22:38 |
|  7 | 1643974875942912 | 投票   | 1111112222222 | -4552349083234304 |            1 |      1 | 2022-07-05 20:52:34 | 2022-07-05 20:52:34 |
|  8 | 1644037979246592 | lllk   | 1111112222222 | -4552349083234304 |            1 |      1 | 2022-07-05 20:52:49 | 2022-07-05 20:52:49 |
|  9 | 1644081310601216 | qqqql  | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-05 20:52:59 | 2022-07-05 20:52:59 |
| 10 | 1644113220866048 | hello  | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-05 20:53:07 | 2022-07-05 20:53:07 |
| 11 | 8813050287099904 | hello  | 1111112222222 | -4552349083234304 |            2 |      1 | 2022-07-25 15:39:54 | 2022-07-25 15:39:54 |
+----+------------------+--------+---------------+-------------------+--------------+--------+---------------------+---------------------+
11 rows in set (0.00 sec)

mysql> show processlist;
+----+------+-----------------+----------+---------+------+----------+------------------+
| Id | User | Host            | db       | Command | Time | State    | Info             |
+----+------+-----------------+----------+---------+------+----------+------------------+
|  6 | root | localhost:63386 | bluebell | Query   |    0 | starting | show processlist |
+----+------+-----------------+----------+---------+------+----------+------------------+
1 row in set (0.00 sec)

mysql> explain select * from user;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+
|  1 | SIMPLE      | user  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    2 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------+

type:表示MySQL在表中找到所需行的方式,或者叫访问类型

  • type=ALL,全表扫描,MySQL遍历全表来找到匹配行
  • type=index,索引全扫描
  • type=range,索引范围扫描
  • type=eq_ref,唯一索引
  • type=NULL,MySQL不用访问表或者索引,直接就能够得到结果(性能最好)

possible_keys: 表示查询可能使用的索引
key: 实际使用的索引
key_len: 使用索引字段的长度
rows: 扫描行的数量
Extra

  • using index:覆盖索引,不回表
  • using where:回表查询
  • using filesort:需要额外的排序,不能通过索引得到排序结果

优化

如果大多数时间都正常,偶尔很慢,那可能是,数据库在刷新脏页,例如 log redo写满了,需要同步到磁盘。或者执行的时候遇到了锁,或者本次sql写的不对。如果一直执行很慢,那有可能是没用索引,或者索引失效。这时我们需要结合具体的手段去定位慢sql。