mysql慢查询分析

192 阅读17分钟

mysql执行计划分析

  • 客户端发送一条查询语句(SELECT)到mysql,首先会去查询缓存,若缓存未开启会经过解析器(对SQL语句进行解析以及mysql语法规则校验), 然后到查询优化器(将SQL语句的解析树,转化成执行计划,可能会生成多条执行计划,mysql采用基于成本的优化,选择最优的执行计划),最后将执行计划发送到执行器,调用存储引擎的api接口,完成SQL语句的调用

  • mysql采用基于成本的优化,对于一条SQL语句会生成多条执行计划,优化器会统计每一条执行计划的执行成本,然后采用最优(成本最低)的执行计划

  • 查询SQL的查询执行计划,在select语句加上explain,即explain select ......或者explain format=json select .......来查询该条查询语句对应的执行计划(包含某个计划mysql的预估成本)

  • 通过show profiles来分析当前会话中sql语句执行的资源消耗情况的工具,可用于sql调优的测量。默认情况下处于关闭状态,并保存最近15次的运行结果。开启后只会存在当前会话。

    • show profile cpu,block io for query Query_ID;/Query_ID为#3步骤中show profiles列表中的Query_ID,来查询Query_ID对应的SQL语句时的,成本开销。/
    • show profiles能查询到的成本开销包括
      • ALL: 显示所有的开销信息
      • BLOCK IO : 显示块IO开销
      • CONTEXT SWITCHES : 上下文切换开销
      • CPU: CPU开销信息
      • IPC: 显示发送和接收的开销信息
      • MEMORY: 显示内存开销信息
      • PAGE FAULTS: 显示页面错误的开销信息
      • SOURCE: 显示Source_function,Source_file,Source_line相关的开销信息
      • SWAPS: 显示交换次数开销
    • 通过show profile 命令对耗时时间长的sql语句进行诊断,来判断是否需要优化SQL语句
      • converting HEAP to MYLSAM : 查询结果太大,内存不够,导致数据存入了磁盘
      • Creating tmp table : 创建临时表,先将数据拷贝到临时表,用完后在删除临时表
      • Copying to tmp table on disk: 将内存中临时表复制到磁盘中
mysql> show profile ALL for query 2;
+----------------------+-----------+-----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| Status               | Duration  | CPU_user  | CPU_system | Context_voluntary | Context_involuntary | Block_ops_in | Block_ops_out | Messages_sent | Messages_received | Page_faults_major | Page_faults_minor | Swaps | Source_function       | Source_file          | Source_line |
+----------------------+-----------+-----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
| starting             | 0.000262  | 0.000723  | 3E-6       |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | NULL                  | NULL                 | NULL        |
| checking permissions | 5.4E-5    | 0.000149  | 1E-6       |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | check_access          | sql_authorization.cc |         809 |
| checking permissions | 4.7E-5    | 0.000141  | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | check_access          | sql_authorization.cc |         809 |
| Opening tables       | 9.3E-5    | 0.000283  | 2E-6       |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | open_tables           | sql_base.cc          |        5815 |
| init                 | 0.000109  | 0.000348  | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | handle_query          | sql_select.cc        |         128 |
| System lock          | 6.6E-5    | 0.000191  | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_lock_tables     | lock.cc              |         330 |
| optimizing           | 6.8E-5    | 0.000202  | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc     |         158 |
| statistics           | 9.9E-5    | 0.000298  | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc     |         374 |
| preparing            | 7.2E-5    | 0.000213  | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | optimize              | sql_optimizer.cc     |         482 |
| executing            | 4.5E-5    | 0.000129  | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | exec                  | sql_executor.cc      |         126 |
| Sending data         | 10.538471 | 29.660835 | 0.074716   |              1783 |                1958 |        47616 |          1048 |             0 |                 0 |                 0 |              1122 |     0 | exec                  | sql_executor.cc      |         202 |
| end                  | 9.7E-5    | 0.000228  | 1E-6       |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | handle_query          | sql_select.cc        |         206 |
| query end            | 6.6E-5    | 0         | 0.000986   |                 0 |                   1 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command | sql_parse.cc         |        4959 |
| closing tables       | 4.6E-5    | 0         | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_execute_command | sql_parse.cc         |        5018 |
| freeing items        | 8.3E-5    | 0         | 0          |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | mysql_parse           | sql_parse.cc         |        5637 |
| logging slow query   | 9.6E-5    | 0         | 0          |                 0 |                   0 |            0 |             8 |             0 |                 0 |                 0 |                 0 |     0 | log_slow_do           | log.cc               |        1716 |
| cleaning up          | 5.9E-5    | 5.4E-5    | 4E-6       |                 0 |                   0 |            0 |             0 |             0 |                 0 |                 0 |                 0 |     0 | dispatch_command      | sql_parse.cc         |        1933 |
+----------------------+-----------+-----------+------------+-------------------+---------------------+--------------+---------------+---------------+-------------------+-------------------+-------------------+-------+-----------------------+----------------------+-------------+
17 rows in set

mysql>
  • SHOW WARNINGS命令查询与该查询的执行计划有关的信息,当code为1003时,表示Message字段展示是优化器重写后的sql语句。

mysql> explain SELECT err_type from t_ts_macs_web_detail where web_source in(SELECT web_source from t_ts_macs_web_task where user_no = '110000000139279');
  +----+--------------+----------------------+------------+------+-------------------+-------------------+---------+------------------------+------+----------+-------------+
  | id | select_type  | table                | partitions | type | possible_keys     | key               | key_len | ref                    | rows | filtered | Extra       |
  +----+--------------+----------------------+------------+------+-------------------+-------------------+---------+------------------------+------+----------+-------------+
  |  1 | SIMPLE       | <subquery2>          | NULL       | ALL  | NULL              | NULL              | NULL    | NULL                   | NULL |      100 | Using where |
  |  1 | SIMPLE       | t_ts_macs_web_detail | NULL       | ref  | idx_src_mes_atime | idx_src_mes_atime | 387     | <subquery2>.web_source |  299 |      100 | NULL        |
  |  2 | MATERIALIZED | t_ts_macs_web_task   | NULL       | ALL  | IDX_WT_WS         | NULL              | NULL    | NULL                   | 2654 |       10 | Using where |
  +----+--------------+----------------------+------------+------+-------------------+-------------------+---------+------------------------+------+----------+-------------+
  3 rows in set

mysql> show warnings;
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                                  |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `fpstore`.`t_ts_macs_web_detail`.`err_type` AS `err_type` from `fpstore`.`t_ts_macs_web_detail` semi join (`fpstore`.`t_ts_macs_web_task`) where ((`fpstore`.`t_ts_macs_web_detail`.`web_source` = `<subquery2>`.`web_source`) and (`fpstore`.`t_ts_macs_web_task`.`user_no` = '110000000139279')) |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set

索引信息:
t_ts_macs_web_task.web_source  --> IDX_WT_WS
t_ts_macs_web_detail.(web_source, message, add_time)  --> idx_src_mes_atime


mysql> explain SELECT d.err_type from t_ts_macs_web_detail d LEFT JOIN t_ts_macs_web_task t on d.web_source = t.web_source where t.user_no = '110000000139279';
+----+-------------+-------+------------+------+-------------------+-------------------+---------+----------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys     | key               | key_len | ref                  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+----------------------+------+----------+-------------+
|  1 | SIMPLE      | t     | NULL       | ALL  | IDX_WT_WS         | NULL              | NULL    | NULL                 | 2798 |       10 | Using where |
|  1 | SIMPLE      | d     | NULL       | ref  | idx_src_mes_atime | idx_src_mes_atime | 387     | fpstore.t.web_source |  305 |      100 | NULL        |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+----------------------+------+----------+-------------+
2 rows in set


mysql> explain SELECT err_type from t_ts_macs_web_detail where web_source in(SELECT web_source from t_ts_macs_web_task where user_no = '110000000139279');
+----+--------------+----------------------+------------+--------+-------------------+------------+---------+-----------------------------------------+--------+----------+-------------+
| id | select_type  | table                | partitions | type   | possible_keys     | key        | key_len | ref                                     | rows   | filtered | Extra       |
+----+--------------+----------------------+------------+--------+-------------------+------------+---------+-----------------------------------------+--------+----------+-------------+
|  1 | SIMPLE       | t_ts_macs_web_detail | NULL       | ALL    | idx_src_mes_atime | NULL       | NULL    | NULL                                    | 199345 |      100 | Using where |
|  1 | SIMPLE       | <subquery2>          | NULL       | eq_ref | <auto_key>        | <auto_key> | 387     | fpstore.t_ts_macs_web_detail.web_source |      1 |      100 | NULL        |
|  2 | MATERIALIZED | t_ts_macs_web_task   | NULL       | ALL    | IDX_WT_WS         | NULL       | NULL    | NULL                                    |   2800 |       10 | Using where |
+----+--------------+----------------------+------------+--------+-------------------+------------+---------+-----------------------------------------+--------+----------+-------------+
3 rows in set

mysql> explain SELECT err_type from t_ts_macs_web_detail where web_source='itf-fe-cl-web'
union all
SELECT web_source from t_ts_macs_web_task where user_no = '110000000139279';
+----+-------------+----------------------+------------+------+-------------------+-------------------+---------+-------+-------+----------+-------------+
| id | select_type | table                | partitions | type | possible_keys     | key               | key_len | ref   | rows  | filtered | Extra       |
+----+-------------+----------------------+------------+------+-------------------+-------------------+---------+-------+-------+----------+-------------+
|  1 | PRIMARY     | t_ts_macs_web_detail | NULL       | ref  | idx_src_mes_atime | idx_src_mes_atime | 387     | const | 79386 |      100 | NULL        |
|  2 | UNION       | t_ts_macs_web_task   | NULL       | ALL  | NULL              | NULL              | NULL    | NULL  |  2794 |       10 | Using where |
+----+-------------+----------------------+------------+------+-------------------+-------------------+---------+-------+-------+----------+-------------+
2 rows in set


mysql> explain SELECT err_type from t_ts_macs_web_detail where web_source='itf-fe-cl-web'
union 
SELECT web_source from t_ts_macs_web_task where user_no = '110000000139279';
+------+--------------+----------------------+------------+------+-------------------+-------------------+---------+-------+-------+----------+-----------------+
| id   | select_type  | table                | partitions | type | possible_keys     | key               | key_len | ref   | rows  | filtered | Extra           |
+------+--------------+----------------------+------------+------+-------------------+-------------------+---------+-------+-------+----------+-----------------+
|    1 | PRIMARY      | t_ts_macs_web_detail | NULL       | ref  | idx_src_mes_atime | idx_src_mes_atime | 387     | const | 79386 |      100 | NULL            |
|    2 | UNION        | t_ts_macs_web_task   | NULL       | ALL  | NULL              | NULL              | NULL    | NULL  |  2795 |       10 | Using where     |
| NULL | UNION RESULT | <union1,2>           | NULL       | ALL  | NULL              | NULL              | NULL    | NULL  | NULL  | NULL     | Using temporary |
+------+--------------+----------------------+------------+------+-------------------+-------------------+---------+-------+-------+----------+-----------------+
3 rows in set



mysql> explain  SELECT d.err_type from t_ts_macs_web_detail d LEFT JOIN t_ts_macs_web_task t on d.device_id = t.device_id where t.user_no = '110000000139279';

+----+-------------+-------+------------+------+---------------+--------------+---------+---------------------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key          | key_len | ref                 | rows   | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+--------------+---------+---------------------+--------+----------+-------------+
|  1 | SIMPLE      | d     | NULL       | ALL  | NULL          | NULL         | NULL    | NULL                | 195583 |      100 | NULL        |
|  1 | SIMPLE      | t     | NULL       | ref  | IDX_WT_DEVID  | IDX_WT_DEVID | 386     | fpstore.d.device_id |      1 |       10 | Using where |
+----+-------------+-------+------------+------+---------------+--------------+---------+---------------------+--------+----------+-------------+
2 rows in set

mysql> explain SELECT d.err_type from t_ts_macs_web_task t  left JOIN t_ts_macs_web_detail d on d.device_id = t.device_id where t.user_no = '110000000139279';

+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   2646 |       10 | Using where                                        |
|  1 | SIMPLE      | d     | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 195714 |      100 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
2 rows in set

  • 一条sql语句执行计划可能对应多条,比如关联子查询
  • 执行计划分析

    • id
    • select_type
    • table
    • partitions
    • possible_keys
    • key
    • key_len
    • ref
    • rows
    • filtered
    • Extra
  • id

    • id列:反应的是表读取顺序或查询中执行select子句的顺序
      • id相同,可以认为一组,执行顺序由上至下,第一个为驱动表,第二个为被驱动表
      • id不同,如果是子查询,id序号会递增,id值越大优先级越高,越先被执行
  • select_type列: 表示select的查询类型,主要区别于普通查询,联合查询,子查询等复杂查询

    • SIMPLE:简单的查询,不包含子查询或者union
    • PRIMARY: 需要Union操作或含子查询的select查询计划,位于最外层的select_type即为PRIMARY
    • subquery: select或where列表的子查询(不相关子查询),会采用物化的方案来执行该子查询
    • derived(派生表):在from列表中包含的子查询,MySQL会递归执行这些子查询,把结果放在临时表里。
    • union:若第二个select出现在union后,则被标记为union;若union包含在from子句的子查询中,外层select将被标记为derived。
    • union result:union后的结果集。
    • MATERIALIZED:物化子查询;优化器使用物化来实现更加有效的子查询处理,物化通过将子查询结果生成临时表(通常在内存中)<表特别大时会存入到磁盘中>,然后再执行连接查询
  • table

    • 显示这一步访问数据库中表的名称或者是该步骤执行结果得简称
  • type type表示对表的访问方式,称为“访问类型”表示在表中找到所需行的方式

    • 性能由好到坏 system > const > eq_ref > ref > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
    • ALL: 全表扫描以匹配到对应的行
    • index: 全索引扫描,表示只遍历索引树
    • const、system:命中主键或唯一索引,被连接的部分是个常量,该表最多只有一个匹配行,也叫常量查询。system是const类型的特例,即查询表中只有一行数据
    • eq_ref:连接查询,如果被驱动表是通过主键或者唯一索引列等值匹配,则被驱动表访问就是eq_ref
    • ref: 非唯一索引或唯一索引的前缀进行扫描,本质也是一种索引访问,返回所有匹配某个值的单独行或多个符合条件的值。
    • ref_or_null:与ref类似,但是MySQL对包含NULL值的行进行额外的搜索
    • index_merge:索引合并优化,我们的where中可能有多个条件(或者join)涉及到多个字段,它们之间进行 AND 或者 OR,那么此时就有可能会使用到 index merge 技术。index merge 技术如果简单的说,其实就是:对多个索引分别进行条件扫描,然后将它们各自的结果进行合并(intersect/union)<其实是可以通过复合索引进行优化的>。
    • unique_subquery:类似于eq_ref,条件用了in子查询
    • index_subquery:区别于unique_subquery,用于非唯一索引,可以返回重复值
    • range: 范围扫描,一般在where语句出现范围查询
    • null: mysql优化分析时,执行中不需要访问表或索引(例如从索引列选取最小值可以单独索引查找完成)
  • possible_keys

    • 表示此次查询可能用到的索引
  • key

    • 表示此次查询实际用到的索引,若没有走索引则显示null,如果想强制使用或忽略索引可以在查询语句中,使用FORCE INDEX或IGNORE INDEX
  • ref

    • 显示了此次查询真正用的索引,其中索引列中查找值所用的列或常量,如果值为func,则使用的值是某个函数的结果
  • rows

    • 该值表示mysql找到匹配行所需要扫描的行数,是一个预估值并不准确,当回表时,也会被记录在此列。
  • ####filtered
    • 该列是一个百分比的值,表里符合条件的记录数的百分比。简单点说,这个字段表示存储引擎返回的数据在经过过滤后,剩下满足条件的记录数量的比例。
    • mysql在分析连接查询的成本时,有一个计算驱动表扇出时采用的一个策略
      • 如果使用的是全表扫描的方式执行的单表查询,那么计算驱动表扇出时需要估计出满足搜索条件的记录到底有多少条。
      • 如果使用的是索引执行的单表扫描,那么计算驱动表扇出的时候需要估计出满足除使用到对应索引的搜索条件外的其他搜索条件的记录有多少条
    • 如果使用的是索引执行的单表扫描,那么 filtered列表示,查询优化器预估除在满足对应索引列的条件下,其中有filtered * rows行数据满足除对应索引条件外的其他搜索条件。我们更加关注关联查询中的filtered列
    • 比如下面这个,查询优化器将表t当做驱动表,d为被驱动表,表t的执行计划rows为2646,filtered为10,这意味着表t的扇出为2646 * 10% = 264.6这说明还要对被驱动表大约264次查询
mysql> explain SELECT d.err_type from t_ts_macs_web_task t  left JOIN t_ts_macs_web_detail d on d.device_id = t.device_id where t.user_no = '110000000139279';

+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra                                              |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
|  1 | SIMPLE      | t     | NULL       | ALL  | NULL          | NULL | NULL    | NULL |   2646 |       10 | Using where                                        |
|  1 | SIMPLE      | d     | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 195714 |      100 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------------+------+---------------+------+---------+------+--------+----------+----------------------------------------------------+
2 rows in set
  • Extra,此字段包含mysql解析SQL语句的其他一些信息,常见的一些属性值,更多请翻阅官方文档

    • Using filesort: SQL语句出现order by排序,GROUP BY子句,MySQL会在包含GROUP BY子句的查询中默认添加上ORDER BY子句,且指定的排序列与索引列排序不一致,会出现文件排序。数据量小在内存中进行排序,数据量大会进行磁盘文件排序
    • Using temporary: 表示是否使用了临时表,性能特别差,需要重点优化。一般多见于group by语句,或者union语句。
    • Using where: 表示使用了where条件过滤,一般发生在不能走索引扫描的情况下或者走索引扫描,但是有些查询条件不在索引当中的情况下
    • Using index: 表示使用了索引覆盖,只扫描索引树就行
    • Using index condition: MySQL5.6之后新增的索引下推。只合适二级索引,利用二级索引在存储引擎层进行数据过滤,而不是在服务层过滤(即再次判断缩小索引列形成的扫描的范围区间),利用索引现有的数据减少回表的数据
    • Using join buffer: 采用了join buffer来实现表关联查询 join的原理就是嵌套循环连接,驱动表作为第一层,被驱动表作为第二层
      • join查询的优化算法
        • Index Nested-Loop Join : 遍历驱动表的数据,然后取出一条数据,去匹配被驱动表中相匹配的数据(而被驱动表中有索引)
        • Block Nested-Loop Join: 将驱动表的数据加载到内存中(join buffer),然后从被驱动表中取出每一行做匹配(被驱动表列无索引)
    • Using intersect(...)、Using union(...)和Using sort_union(...) :表示使用了intersect,union,sort_union等索引合并的方式进行查询,括号里是索引合并的名称
    • Start temporary, End temporary; LooseScan;FirstMatch(tbl_name);
      • 当优化器将子查询(in 子查询)装换成semi-join时,semi-join不同的执行策略,会导致Extra出现不同的值
      • DuplicateWeedout策略
        • 通过建立临时表实现外层查询记录去重,驱动表查询的执行计划Extra列将显示Start temporary,而被驱动表显示End temporary
      • LooseScan执行策略
        • 驱动表执行计划的Extra列就是显示LooseScan提示
      • FirstMatch执行策略
        • 被驱动表执行计划的Extra列就是显示FirstMatch(tbl_name)

mysql慢SQL优化

  • 发现慢查询SQL

    • 一个SQL的执行时间只要超过long_query_time(单位秒)时,就被认定为时慢SQL;此时只要开启记录慢SQL的开关slow_query_log,并将慢SQL日记文件记录在slow_query_log_file该路径下;
  • SQL优化方向

    • 未使用索引
      • 字段列未添加索引
      • 添加的索引列区分度特别低
      • 索引列失效
        • 索引列发生了隐式装换,mysql官网声明了几种隐式转换
        • 对索引列进行了函数处理,模糊查询时通配符使用不正确,应该对传入的值进行处理(右原则处理)
        • 左右连接,关联字段的编码格式不一样
        • 联合索引使用错误(不满足最左匹配原则,mysql8版本后,新增了一个跳跃索引的概念,不满足最左匹配原则,也有可能使用该联合索引)
      • 优化器选错索引,mysql优化器采用基于成本的方式来选择最优的执行计划,所有存在选错索引的情况;可以使用force index强制选择某个索引
        • in元素过多时,优化器基于成本的考虑会选错索引,或者全表扫描;可以采用分批查询
        • 使用了or,或者查询类型type是range范围扫描时,由于数据量过大,所以优化器基于成本考虑就采用了全表扫描
    • 回表
      • 当select查询列出现非索引列式,采用了二级索引树扫描,需要根据二级索引树的聚簇索引值,进行再次查询,这过程就叫回表。当查询的数据量特别大时,即使采用了索引也可能会很慢
    • limit深度分页
      • mysql分页limit会扫描出钱前offset+n条数据,并丢弃前offset条,返回后n条数据,扫描更多的行数,意味着回表的次数更多
      • 一般可以使用延迟关联法,即先查询出排序结果集的主键,在进行关联查询,减少回表次数
    • 单表数据量过大
      • 单笔数据过大,B+树的层级变高,查询一条数据经历的磁盘IO变多
      • 可以通过分库分表的方法来解决
    • join或子查询过多
      • join算法的问题,BNL算法会导致驱动表的数据加载到内存或磁盘,导致查询很慢,而Index Nested-Loop Join算法(类似于嵌套查询)数据量大时即使用到被驱动表的索引但也会很慢
    • mysql后台正在刷脏页
      • mysql将读入的数据页加载到内存(缓冲池buffer pool),脏页指内存中的页数据和磁盘中对应的页数据不一致就叫做脏页(数据更新引起的)
      • 若一个查询要淘汰的脏页个数太多(即内存buffer pool中脏页过多,不足以加载新的数据页到内存中),此时会触发刷脏页操作,导致查询特别慢
    • 使用了文件排序或者使用了临时表
      • group by 或者order by导致使用了文件排序,排序有两种rowid和全字段排序,第一种rowid会产生回表可能会慢,文件排序会将数据加载到内存(sort_buffer),当数据量大时(超过sort_buffer_size)会借助磁盘,这样产生大量的磁盘IO,从而出现慢SQL
      • group by采用了排序也使用了临时表,临时表加载数据到内存中,不足是会借助磁盘,导致磁盘io;
    • 拿不到锁
      • 表锁,或对应的行加上了排他锁,导致查询等待,致使出现慢SQL;
    • 自身硬件配置或者网络资源压力特别大
      • 服务器硬件配置低,或者服务器负载压力大,比如cpu满载,内存紧张时,会导致mysql服务性能下降
      • 当服务器网络资源紧张(带宽不够)此时传输大数据量时,导致SQL查询慢,所以select查询只查询需要的列,当数据量特别大时,考虑分页查询