zoukankan      html  css  js  c++  java
  • 3、查询性能优化

    一、查询变慢的原因

    Mysql执行查询时会有很多子任务,查询的声明周期大致可以分为:

    从客户端,到服务器,然后在服务器上进行解析,生产执行计划,执行,并返回结果给客户端。

    其中最重要的一环是“执行”,这其中包含了大量为检索数据到存储引擎的调用以及调用后的数据处理,包括排序、分组等。

    查询性能低下最根本的原因是访问的数据太多

    某些查询不可避免地需要筛选大量的数据,但大多数情况,性能低下的查询都可以通过减少访问数据量的方式进行优化。

    1.1.对于性能低下的查询,一个有效的手段是通过下面两步来进行分析

    • 确认应用程序是否在检索超过需要的数据,通常意味着访问太多的行,但也会有时候访问太多的列
    • 确认mysql服务器层是否在分析大量超过需要的数据行。

    请求不需要的数据会造成多项资源的浪费,如网络开销、CPU以及内存资源等。一定不要有select * 这样的语句。

    1.2.判断mysql是否做了大量额外的扫描

    有三个指标衡量其开销:

    1、 响应时间

    响应时间 = 服务时间 + 排队时间。服务时间是查询真正话费的时间,排队时间是由于资源竞争,如IO或锁,等待执行的时间。目前的mysql无法精确计算各个部分的时间,因此,在不同类型的应用压力下,响应时间没有统一的规律或公式。

    2、 扫描行数

    3、 返回行数

    分析扫描行数和返回行数,在一定程度上说明了查询效率高不高

    理想状态,扫描行数和返回行数是相同的,但更常见的情况是,扫描的行数和返回的行数比值在1:1到10:1之间,有时会更大。

    1.3.扫描的行数和访问类型

    一个合适的索引。可以让查询使用合适的访问类型,尽可能只扫描需要的数据行。

    当我们发现了查询需要扫描大量的数据但是只返回了少数的行,那么通常可以尝试下面的技巧优化:

    1、 使用索引覆盖扫描。把所有需要的列都放到索引中,这样存储引擎无须回表获取对应行就可以返回结果了

    2、 改变库表结构。例如使用单独的汇总表

    3、 重写这个复杂的查询

    二、重构查询的方式

    在优化有问题的查询时,目标应该是找到一个更优的方法获取实际需要的结果,而不一定总是需要从mysql获取一模一样的结果集。

    设计查询时,一个需要考虑的重要问题是,复杂查询或多个简单查询。传统实现中,总是强调在数据库中完成尽可能多的工作,原因在于减少网络通信、查询解析和优化等被认为是代价很高的事情。在其他条件都相同的情况下,尽量减少查询当然是好的。但有时候,将一个大查询分解为多个小查询也是必要的,

    2.1切分查询

    切分查询是指,将大查询切分成小查询功能完全一样,只完成一小部分,每次只返回一小部分查询结果。

    例如,delete删除旧数据,如果一次删除大量数据,则可能需要一次锁住很多数据,占满整个事务日志,耗尽系统资源,阻塞很多小的但很重要的查询

    Delete from message where created < date_sub(now(), interval 3 month);

    如果切分成多个小的执行语句,并设置适当的时间间隔,就可以大大降低对服务器的影响。

    2.2分解关联查询

    很多高性能的应用都会对关联查询进行分解

    简单的说,就是每一个表进行一次单表查询,然后将结果在应用程序中进行关联。

    这样做的好处有一下几点

    1、 执行单个查询可以减少锁的竞争

    2、 在应用层做关联,可以更容易对数据库进行拆分,更容易做到高性能和可扩展

    3、 查询本身效率也可能有所提升

    4、 可以减少冗余记录的查询。应用层做关联,意味着某些记录只需要查询一次,而在数据库中做关联,则可能需要反复地访问这些记录。这样做相当于在应用中实现了哈希关联,而不是使用mysql的嵌套循环关联。

    使用场景

    1、 应用能够方便地缓存单个查询结果

    2、 数据分布于多个mysql服务器上

    3、 能够使用in()的方式代替关联查询。形如select xxx from x where id in (select 。。。)这样的子查询

    4、 当查询中使用同一个数据表。自关联

    分解关联查询举例

    Select * from tag

           Join tag_post on tag_post.tag_id = tag.id

           Join post on tag_post_tag_id = post_id

    Where tag.tag = ‘myql’;

    可以分解为

    Select * from tag where tag = ‘mysql’

    Select * from tag_post where tag_id = 1234

    Select * from post where post_id in (123,456,567,9098,8904)

     

    关联子查询优化

    其实很多的关联子查询是非常糟糕的,最糟的是 where 后面跟 in的子查询,一般像这样的子查询建议使用left join来实现

    在优化关联查询的时候需要注意的几点是:

    1、确保ON 或 USING子句中的列上有索引。在创建索引的时候就要考虑到关联的顺序。当表A和表B用列c关联的时候,如果优化器的关联顺序是B、A,那么就不需要在B表的对应列上建立索引。没有用到的索引只会带来额外的负担。一般来说,除非有其他原因,否则只需要在关联顺序中的第二个表的相应列上创建索引。

    2、确保任何的GROUP BY 和 ORDER BY 中的表达式只涉及到一个表中的列,这样MySQL才能有可能使用索引来优化这个过程。

    对最大值,最小值的优化,

    很多情况下,对一个字段求他的最大值,最小值,我们会用函数去做,但是这样的情况并不是最好的,比如有些场景,就是我们可以知道这个查询字段如果是索引的话,那么索引本身就是有排序的,那么我们只需要把他排序好,取limit 1 比用 函数会好很多。

    对count的优化

    最好的查询结果的行数的方式就是count(*),因为底层做了优化的。

    按照效率排序的话,count(字段)<count(主键 id)<count(1)≈count(*),所以尽量使用 count(*)。

    提前终止查询。

    在发现已经满足查询需求时,MySQL总是能立刻终止查询。一个典型是,使用了LIMIT子句。除此之外,MySQL还有几种情况,例如发现一个不成立的条件,MySQL就会立刻返回空结果。如果发现某些特殊条件,则会提前终止查询。当存储引擎需要检索“不同取值”或判断存在性的时候。

    union的限制

    MySQL有时候无法将外层限制条件“下推”到内层,使得原本能够限制部分返回结果的条件无法应用到内层查询的优化上。

    如果希望UNION 的各个子句能够根据LIMIT只取部分结果集,或者希望能够先排好序再进行合并的话,就需要在UNION的各个子句中分别使用这些子句。

     

    三、连接的原理

    嵌套循环连接(Nested-Loop Join)

    对于两表连接来说,驱动表只会被访问一遍,但被驱动表却要被访问到好多遍,具体访问几遍取决于对驱动表执行单表查询后的结果集中的记录条数。对于内连接来说,选取哪个表为驱动表都没关系,而外连接的驱动表是固定的,也就是说左(外)连接的驱动表就是左边的那个表,右(外)连接的驱动表就是右边的那个表:

    • 步骤1:选取驱动表,使用与驱动表相关的过滤条件,选取代价最低的单表访问方法来执行对驱动表的单表查询。
    • 步骤2:对上一步骤中查询驱动表得到的结果集中每一条记录,都分别到被驱动表中查找匹配的记录。

    如果有3个表进行连接的话,那么步骤2中得到的结果集就像是新的驱动表,然后第三个表就成为了被驱动表,重复上边过程,也就是步骤2中得到的结果集中的每一条记录都需要到t3表中找一找有没有匹配的记录,用伪代码表示一下这个过程就是这样:

     

    for each row in t1 {

    #此处表示遍历满足对t1单表查询结果集中的每一条记录

    for each row in t2 {

    #此处表示对于某条t1表的记录来说,遍历满足对t2单表查询结果集中的每一条记录

    for each row in t3 {

    #此处表示对于某条t1和t2表的记录组合来说,对t3表进行单表查询

    if row satisfies join conditions, send to client }

    }

    }

    使用索引加快连接速度

    比如说在被驱动表上建立索引,让他们的查询类型变成 cast 或者是ref 这样就能加快查询速度了

    基于块的嵌套循环连接(Block Nested-Loop Join)

    提前划出一块内存(join buffer)存储驱动表结果集中的记录,然后开始扫描被驱动表,每一条被驱动表的记录一次性和这块内存中的多条驱动表记录匹配,可以显著减少被驱动表的I/O操作。

     

     

     

     

    Linux等环境软件安装
  • 相关阅读:
    从零开始webpack4.x(五) js处理
    从零开始webpack4.x(四)样式loader
    从零开始webpack4.x(三)html插件
    从零开始webpack4.x(二)基础
    从零开始webpack4.x(一)介绍
    【转】react和vue渲染流程对比
    css3相关
    html5相关
    this指向
    整数划分问题(递归)
  • 原文地址:https://www.cnblogs.com/Adam-Ye/p/14850918.html
Copyright © 2011-2022 走看看