MySQL查询性能优化

2020-01-05  本文已影响0人  Karl90

1. 为什么查询速度慢

一个查询是由许多子任务组成的,每个子任务都会消耗一定的时间。优化一个查询,其实就是要优化其子任务。

  • 一个查询的生命周期步骤:

    1. 客户端发送一条查询给MySQL服务器

    2. MySQL服务器先检查查询缓存

      • 如果命中缓存,则立刻返回存储在查询缓存中的结果给客户端
      • 否则,进行下一阶段
    3. 解析器进行SQL解析,生成解析树

    4. 预处理器验证权限,确认合法的解析树

    5. 查询优化器根据解析树进行优化,生成对应的查询执行计划

    6. 查询执行引擎根据查询优化器生成的查询执行计划,调用存储引擎的API接口执行查询

    7. 存储引擎数据文件中查询相应数据返回给查询执行引擎

    8. 查询执行引擎存储引擎的API接口返回的结果进行处理

      • 将结果存入查询缓存

      • 将结果返回给客户端

  • 查询花费时间的地方包括:

    • 网络

    • CPU计算

    • 生成统计信息

    • 生成执行计划

    • 锁等待(互斥等待)

    • 向底层存储引擎检索数据的调用操作

      • 内存操作
      • CPU操作
      • 内存不足时导致的I/O操作
    • 上下文切换

    • 系统调用

  • 遇到的问题可能包括:
    • 不必要的额外操作
    • 某些操作被额外地重复了很多次
    • 某些操作执行的太慢
  • 优化查询子任务的思路:
    • 消除其中一些子任务
    • 减少子任务的执行次数
    • 让子任务运行更快

2. 优化数据访问

查询性能低的最基本原因是访问数据太多,可以从两个步骤分析:

  1. 确认应用程序是否在检索大量超过需要的数据

    • 访问了太多的行
    • 访问了太多的列
  2. 确认MySQL服务器是否分析大量超过需要的数据行

1. 是否向数据库请求了不需要的数据

2. MySQL是否在扫描额外的记录

在确定查询只返回需要的数据后,需要查看查询为了返回结果是否扫描了过多的数据。

衡量查询开销的指标:

  • 响应时间

    • 服务时间

    • 排队时间

      • I/O
      • 锁等待(行锁、表锁)

    判断响应时间是否是合理的值(快速上限估计法)

  • 扫描的行数和反回的行数

  • 扫描的行数和返回的类型

    • EXPLAIN语句中的type列反应了访问类型(速度从慢到快、扫描的行数从多到少):

      • 全表扫描
      • 索引扫描
      • 范围扫描
      • 唯一索引查询
      • 常数引用
    • 一般MySQL能够使用如下三种方式应用WHERE条件,从好到坏依次为:

      • 在索引中使用WHERE条件过滤不匹配的记录。(在存储引擎层完成)
      • 使用索引覆盖扫描(在Extra中出现Using index)返回记录,直接从索引中过滤不需要的记录并返回命中的结果。这是在MySQL服务器层完成的,无需再回表查询记录。
      • 从数据表中返回数据,然后过滤不满足条件的记录(在Extra中出现Using where)。这是在MySQL服务器层完成的,MySQL需要先从数据表读取记录然后过滤。
    • 如果发现查询需要扫瞄大量数据但只返回少数的行,通常可以尝试以下技巧:

      • 使用索引覆盖扫描,把所有需要用到的列都放到索引中,这样存储引擎无需回表获取对应的行就可以返回结果。
      • 改变库表结构,比如使用单独的汇总表。
      • 重写复杂的查询,让MySQL优化器能够以更优化的方式执行查询。

3. 重构查询的方式

4. 查询执行

使用SHOW FULL PROCESSLIST命令查看当前状态:

5. 优化特定的查询类型

1. 优化COUNT()查询类型

2. 优化关联查询

3. 优化子查询

​ 5.6版本以前尽可能使用关联查询。

4. 优化GROUP BYDISTINCT

5. 优化LIMIT分页

问题:偏移量大时会抛弃前面大量的数据。

解决方法:

6. 优化UNION查询

MySQL总是通过创建并填充临时表的方式来执行UNION查询。

上一篇下一篇

猜你喜欢

热点阅读