查看慢查询是否开启

  1. show variables like '%slow_query_log';

开启慢查询

  1. set global slow_query_log='ON';

看下慢查询的时间阈值设置

  1. show variables like '%long_query_time%';

想把时间缩短,比如设置为 3 秒

  1. set global long_query_time = 3;

使用 EXPLAIN 查看执行计划

序号 列名 含义
0 select_type SELECT 查询的类型.
1 partitions 匹配的分区
2 type join 类型
3 possible_keys 此次查询中可能选用的索引
4 key 此次查询中确切使用到的索引.
5 ref 哪个字段或常数与 key 一起被使用
6 rows 显示此查询一共扫描了多少行. 这个是一个估计值.
7 filtered 表示此查询条件所过滤的数据的百分比
8 extra 额外的信息
9 key-len 使用到索引字段的长度

select_type

select_type 表示了查询的类型, 它的常用取值有:

  • SIMPLE, 表示此查询不包含 UNION 查询或子查询
  • PRIMARY, 表示此查询是最外层的查询
  • UNION, 表示此查询是 UNION 的第二或随后的查询
  • DEPENDENT UNION, UNION 中的第二个或后面的查询语句, 取决于外面的查询
  • UNION RESULT, UNION 的结果
  • SUBQUERY, 子查询中的第一个 SELECT
  • DEPENDENT SUBQUERY: 子查询中的第一个 SELECT, 取决于外面的查询. 即子查询依赖于外层查询的结果.

type

type 字段比较重要, 它提供了判断查询是否高效的重要依据依据. 通过 type 字段, 我们判断此次查询是 全表扫描 还是 索引扫描 等.

type 说明
all 全表扫描,mysql 遍历全表来找到匹配的行:
index 索引全扫描,mysql 遍历整个索引来查询匹配的行
range 索引范围扫描,常见于<、<=、>、>=、between等操作:
ref 根据索引查找一个或多个值,通常出现在多表的 join 查询, 针对于非唯一或非主键索引, 或者是使用了 最左前缀 规则索引的查询.
index_merge 合并索引,使用多个单列索引搜索
eq_ref 使用primary key 或unique类型,常用于多表联查
const 针对主键或唯一索引的等值查询扫描, 最多只返回一行数据. const 查询速度非常快, 因为它仅仅读取一次即可.
system 表中只有一条数据. 这个类型是特殊的 const 类型.

all 是最坏的情况,因为采用了全表扫描的方式。index 和 all 差不多,只不过 index 对索引表进行全扫描,这样做的好处是不再需要对数据进行排序,但是开销依然很大。如果我们在 Extral 列中看到 Using index,说明采用了索引覆盖,也就是索引可以覆盖所需的 SELECT 字段,就不需要进行回表,这样就减少了数据查找的开销。

image.png

image.png

慢查询分析

  • 先对 sql 语句进行 explain,查看语句存在的问题
  • 使用 show profile 查看执行耗时,分析具体耗时原因

数据库瓶颈


  1. IO 瓶颈 第一种:磁盘读 IO 瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的 IO,降低查询速度 -> 分库和垂直分表。

第二种:网络 IO 瓶颈,请求的数据太多,网络带宽不够 -> 分库。

  1. CPU 瓶颈 第一种:SQL 问题,如 SQL 中包含 join,group by,order by,非索引字段条件查询等,增加 CPU 运算的操作 -> SQL 优化,建立合适的索引,在业务 Service 层进行业务计算。

第二种:单表数据量太大,查询时扫描的行太多,SQL 效率低,CPU 率先出现瓶颈 -> 水平分表。