高性能MYSQL(四)

可以通过explain 语句来对查询进行查看.对可优化的地方做出改进

前言

优化的主要组成部分:

  • 查询语句的优化
  • 索引设计的优化
  • 库表设计的优化

一个查询操作实际上是多个子任务组成,优化查询实际上是优化子任务的执行

  • 一个查询的子任务清单:

    • 网络IO
    • 磁盘IO
    • CPU计算
    • 互斥锁等待

优化数据访问

避免存储多余数据

  • 避免大量无用数据存在于数据表中,加大查询语句的执行复杂度
  • 避免大量无用的行

避免无用的查询

  • 例如在分页查询时,添加合适的LIMIT
  • 联查时只取出有用的数据,避免下面的“一把抓“式的请求
SELECT * FROM A INNER JOIN B WHRER A.ID = B.A_ID
  • 按需取出响应的列
  • 添加缓存
  • 在慢查询日志中,分析一个查询的查询时间是否合理可以利用快速上限法进行估量: 估算这个查询大约会经过的随机IO数 * 具体硬件下一次IO的时间,对查询进行估计
  • 优化联查!优化联查!联查时扫描的行是 矩阵式的 M * N ,很恐怖,所以找到好的对饮关系是优化联查的

重构查询时的方式

一个复杂的查询还是多个简单的查询

对于mysql 来说,MYSQL从设计上让连接和断开链接都很轻量级,在返回一个小的查询结果方面很高效。对于网络链接来说现代网络链接的效率相对与磁盘IO的效率来说已经不是问题。通常来将,两者的区别不仅仅在于传输速度,磁盘IO在查询时还有Lookup的过程。

对于复杂的查询来说,将其分解成多个简单的查询。或许效率更快些。但是同样的,具场景具体分析

将复杂的操作切分带来的另一个好处是可以分解复杂操作长时间对于读/写锁长时间占有,从而避免影响其他业务操作的执行

高性能MYSQL(四)_第1张图片
image.png
  1. 客户端发送一条查询给服务器
  2. 服务器首先查询缓存。如果命中,则立即返回存储在存储在缓存中的结果。否则进入下一阶段
  3. 服务器端进行SQL解析,预处理,再由优化器生成对应的执行计划
  4. MYSQL根据优化器生成的执行计划,调用存储引擎的API来执行查询
  5. 将结果集返回给客户端

MYSQL 客户端和服务器端通信

总的来说,MYSQL客户端和服务器端是一个半双工的通信状态,也就是说,在同一个时间,只能有一端像另一端发送数据(不要被JDBC的线程池的概念混淆)

SHOW ALL PROCESSLIST

各个MYSQL链接对应的状态 :

  • SLEEP : 线程正在等待客户端发送新的请求
  • QUERY : 线程正在执行查询或者正在将结果发送给客户端
  • LOCKED : 线程正在等待表锁
  • Sending Data : 这表示多种情况: 线程可能在多个状态之间传送数据,或者在 生成结果集,或者在客户端返回数据

查询缓存

查询缓存是通过一个对 大小写敏感的哈希查找实现的。如果缓存中缓存有对应数据。数据会直接返回给客户端。

  • 上面的这个大小写敏感,不代表SQL语法关键字敏感。
  • 虽然语法检查在查询缓存之后,但是你可以考虑到这一点。语法错误的查询在第一次执行的就没成功,就不会有缓存!

查询处理优化

查询的下一周期是将一个SQL 转换为一个执行计划,MYSQL再依照这个计划和存储引擎进行交互。这包括多个子阶段:解析SQL,预处理,优化SQL执行计划。

语法解析器和预处理

阶段所做工作

  • 语法解析器负责语法检查
  • 预处理器根据MYSQL规则 进一步检查 解析树是否合法,例如检查数据表和数据列是否存在,还会解析名字和别名,看他们是否有歧义

查询优化器

  • 可以通过 show status like 'Last_query_cost'的值来得知MYSQL计算的当前查询的成本
explain SELECT * FROM commonservice.regions where amapid is not  null;

show  status like 'Last_query_ cost'
Variable_name Value
'Last_query_cost' '142998.599000'

上面的查询结果上面的查询需要 142998个数据页的随机查找才能完成这个查询。当然这只是查询优化器的评估结果,且优化器在评估时不会考拉

  • 影响MYSQL 错误选择执行计划的因素

    • 统计信息不准确,例如:InnoDB因为其MVCC的架构,并不能维护一个数据表的行数的精确统计信息
    • 执行计划中的成本估算不等于实际执行计划,也就是说优化器给出的执行计划也可能不是最优的,比如说,有些页面读取虽多,但是其页面大部分都是顺序读写。
    • MYSQL 从不考虑其他并发执行的查询,这可能会影响当前查询速度
      MYSQL 的查询优化的优化策略分为两种
  • 静态优化 : 静态优化不依赖于特别的数值,如WHERE 条件中带入的一些常数等,静态优化在第一次完成后就一直有效,即使使用不同的参数重复查询也不会发生变化,可以将静态优化认为是一种 “编译时优化”

  • 动态优化 : 动态优化则和查询的上下文有关,例如WHERE 条件中的取值,索引中条目对应的数据行数等,这需要在每次查询的时候重新评估 可以将动态优化认为是一种”运行时优化“

MYSQL能够优化的的类型

重新定义关联表的顺序 : 数据表的关联并不是按照在查询中指定的顺序执行
将外链接转换为内链接 : 并不是所有的OUTER JOIN 语句都必须以外链接的方式执行。例如,WHERE条件,库表结构都可能会让外链接等价于一个内连接

  • 使用等价变换规则 利用等价变换来简化病规范表达式
  • 优化COUNT() ,MIN() ,MAX() : 通过B-Tree索引 直接查找其中的一个方向
  • **预估并转化为常数表达式 : **
  • 覆盖索引扫描 : 当索引中的列包含查询中需要的列,MYSQL会直接返回索引对应的列,不再去查表
  • **子查询优化 : ** Mysql 在某些情况下可以将子查询转换为一种效率更高的形式,从而减少多个查询对数据进行访问
  • 提前终止查询: 当发现已经满足查询需求的时候,MYSQL 总是能够立刻终止查询。比如使用LIMIT语句或者发现了一个不成立的条件,这时候MYSQL会立即返回一个空结果
  • 列表IN ()的优化 : ** 在MYSQL 中,MYSQL首选将IN()列表中的数据先进行排序,然后通过二分查找的方式来确定列表中的值是否满足条件(时间复杂度 : O(lgN) ),如果等价的转换为OR操作的话,时间复杂度为 O(n) :所以说 单列 多值匹配时,利用IN () 效率会更高**

Mysql 如果执行关联查询

  • 对于UNION查询,MYSQL先将一系列的单个查询结果放到一个临时表中,然后再读出临时表中数据完成UNION查询

执行计划 : MYSQL 并不会生成查询字节码来执行查询。MYSQL生成查询的一颗指令树,然后通过存储引擎执行完成这可指令树并返回结果。最终执行计划包含了重构查询的全部信息

优化特定类型的查询

优化COUNT()查询
  1. 如果想要查询行数,使用count() 进行查询,如果在count()函数中指定了某列,查询的是这个列有值(非 NULL)的值的个数!
优化关联查询
  1. 确保ON或者USING 子句的列上有索引,一般来说,除非有其他理由,否则只需要在关联顺序中的第二个表上建立索引
  2. 确保仁和Group by 或者Order by中的表达式只涉及到一个表中的列
GROUP By 和 DISTINCT
  1. 在无法使用索引的时候,GROUP BY使用临时表或者文件排序来分组
  2. 如果需要对 关联查询做分组,并且是按照查找表中的某个列进行分组,那么通常采用查找表的标识列分组的效率比其他列更高

你可能感兴趣的:(高性能MYSQL(四))