zoukankan      html  css  js  c++  java
  • MYSQL之高性能的mysql(六)--查询性能优化

    查询性能优化

    为什么查询速度会慢

      如果把查询看作是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间。如果要优化查询,实际上要优化其子任务,要么消除其中一些子任务,要么减少子任务的执行次数,要么让子任务运行得更快。

    慢查询基础:优化数据访问

    查询性能低下最基本的原因是访问的数据太多.对于低效的查询,我们可以进行以下判断
      1.应用程序是否在检索大量超过需要的数据
      2.确认mysql服务层是否在分析大量超过需要的数据行

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

      查询不需要的记录
      多表关联时返回全部列
      总是取出全部列
      重复查询相同的数据

    如果发现查询需要扫描大量的数据但只返回少数的行,那么通常可以尝试下面的技巧去优化它:
      使用索引覆盖扫描,把所有需要用的列都放到索引中,这样存储引擎无须回表获取对应行就可以返回结果了。
      改变库表结构。例如使用单独的汇总表。
      重写这个复杂的查询,让MySQL优化器能够以更优化的方式执行这个查询。

    重构查询的方式

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

      在传统实现中,总是强调数据库完成尽可能多的操作,这样做的逻辑在于以前总是认为网络通信,查询解析和优化是一件代价很高的事情; 
      但是这样的想法对于mysql并不适用,mysql在连接和断开设计的很轻量,在返回一个小的查询结果方面很高效
      Mysql内部每秒能够扫描内存中数百万行数据,相比之下,mysql响应数据给客户端就慢得多,其他情况相同时,减少查询当然更好,但是有时候,将一个大查询分解成多个小查询是有必要的

    切分查询

      有时候对于一个大查询我们需要“分而治之”,将大查询切分成小查询,每个查询功能完全一样,只完成一小部分,每次只返回一小部分查询结果。

      eg 将一个大的delete分成多个小的

    分解关联查询

    用分解关联查询的方式重构查询有以下优势:
      1.让缓存效率更高
      2.查询分解后,丹哥查询可以减少锁的竞争
      3.应用层做关联,更容易对数据库进行拆分,更容易做高性能和扩展
      4.减少冗余记录的查询寻
      5.避免嵌套关联

    查询执行的基础

    1. 客户端发送一条查询给服务器。
    2. 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段。
    3. 服务器端进行SQL解析、预处理,再由优化器生成对应的执行计划。
    4. MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询。
    5. 将结果返回给客户端。 

    MySQL客户端/服务器通信协议

      MySQL客户端和服务器之间的通信协议是“半双工”的。意味着,在任意时刻,要么服务器向客户端发送数据,要么客户端向服务端发送数据,两个动作不能同时进行。
      多数连接mysql的库函数都可以获得全部结果集并缓存到内存中,还可以逐行获取需要的数据,默认是一般将获得全部结果集并缓存到内存后中.mysql通常会等到所有数据发送客户端才释放链接,所以接受结果全部缓存可以减少服务器压力,让查询早点结束,早点释放资源但使用内存又会带来另一个问题,因为库函数需要花很多时间和内存储存所有结果。

    查询状态

      SHOW FULL PROCESSLIST

    Sleep 

      线程正在等待客户端发送新的请求。

    Query

      线程正在执行查询或者正在将结果发送给客户端。

    Locked

      在MySQL服务器层,该线程正在等待表锁。在存储引擎级别实现的锁,例如InnoDB的行锁,并不会体现在线程状态中。对于MyISAM来说这是一个比较典型的状态,但在其他没有行锁的引擎中也经常会出现。

    Analyzing and statistics

      线程正在收集存储引擎的统计信息,并生成查询的执行计划。 

    The thread is

      线程正在对结果集进行排序。

    Sending data

      这表示多种情况:线程可能在多个状态之间传送数据,或者在生成结果集,或者在向客户端返回数据。

    查询优化处理

    重新定义关联表的顺序,将外连接转换内连接,使用等价变换规则,优化count() min() max(),预估并转化为常数表达式,使用覆盖索引扫描,子查询优化,提前终止查询,等值传播,列表in()比较

    优化特定类型的查询

    优化COUNT()查询

      COUNT() 是一个特殊的函数,有两种非常不同的作用:它可以统计某个列值的数量,也可以统计行数。在统计列值时要求列值是非空的(不统计NULL )。如果在COUNT() 的括号中指定了列或者列的表达式,则统计的就是这个表达式有值的结果数
      通常来说,COUNT() 都需要扫描大量的行(意味着要访问大量数据)才能获得精确的结果,因此是很难优化的。除了前面的方法,在MySQL层面还能做的就只有索引覆盖扫描了。如果这还不够,就需要考虑修改应用的架构,可以增加汇总表,或者增加类Memcached 这样的外部缓存系统。

    优化关联查询

      确保ON 或者USING 子句中的列上有索引。在创建索引的时候就要考虑到关联的顺序。当表A 和表B 用列c 关联的时候,如果优化器的关联顺序是B、A ,那么就不需要在B表的对应列上建上索引。没有用到的索引只会带来额外的负担。一般来说,除非有其他理由,否则只需要在关联顺序中的第二个表的相应列上创建索引。
      确保任何的GROUP BY 和ORDER BY 中的表达式只涉及到一个表中的列,这样MySQL才有可能使用索引来优化这个过程。
      当升级MySQL的时候需要注意:关联语法、运算符优先级等其他可能会发生变化的地方。因为以前是普通关联的地方可能会变成笛卡儿积,不同类型的关联可能会生成不同的结果等。

    优化子查询

      MySQL5.6或更新的版本或者MariaDB之前版本,尽可能使用关联查询代替。

    优化GROUP BY 和DISTINCT

      group by 通常使用查找表的标识进行分组效率更高

    优化LIMIT分页

    当偏移量特别大时,性能有很大影响
      1.尽可能利用覆盖索引
      2.尽可能转换成已知位置
      3.通过主键id能确认更好

    优化union

      如果一定需要服务器处理重复行,否则一定要带上all, 因为没有all关键字,mysql会给临时表加上distinct选项,导致临时表做唯一性检测

    静态查询分析

      Percona Toolkit中的pt-query-advisor 能够解析查询日志、分析查询模式,然后给出所有可能存在潜在问题的查询,并给出足够详细的建议。

    使用用户自定义变量(以下场景尽量不要使用)

      1.使用自定义变量查询,不能使用查询缓存
      2.不能再常量或者标识符地方自定义变量,如表名,列名和limit子句
      3.如果使用连接池或者持久性连接,自定义变量可能引起bug
      4.5.0版本前大写小写敏感
      5.不能显式地声明常量类型
      6.mysql优化器会在某些场景优化掉变量
      7.:=优先级很低
      8.使用未定义的比那辆不会有语法错误
      9.赋值的顺序和赋值的时间点不固定

    避免重复查询刚刚更新的数据

      在更新行的同时又希望获得该行的信息--UPDATE t1 SET lastUpdated = NOW() WHERE id = 1 AND @now := NOW(); SELECT @now;
      上面看起来仍然需要两个查询,需要两次网络来回,但是这里的第二个查询无须访问任何数据表,所以会快非常多。(如果网络延迟非常大,那么这个优化的意义可能不大,不过对这个客户,这样做的效果很好。)

  • 相关阅读:
    读书笔记--SQL必知必会21--使用游标
    读书笔记--SQL必知必会20--管理事务处理
    读书笔记--SQL必知必会19--存储过程
    读书笔记--SQL必知必会18--视图
    PopupWindow
    android shape的使用
    带删除小图标的EditText
    Android点击EditText文本框之外任何地方隐藏键盘的解决办法
    Android px、dp、sp之间相互转换
    android edittext不弹出软键盘
  • 原文地址:https://www.cnblogs.com/kujiawei/p/13865861.html
Copyright © 2011-2022 走看看