mysql笔记03 查询性能优化

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql笔记03 查询性能优化相关的知识,希望对你有一定的参考价值。

查询性能优化

1. 为什么查询速度会慢?

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

    2). 通常来说,查询的生命周期大致可以按照顺序来看:从客户端,到服务器端,然后在服务器上进行解析,生成执行计划,执行,并返回结果给客户端。其中"执行"可以认为是整个生命周期中最重要的阶段,这其中包括

         大量为了检索数据到存储引擎的调用以及调用后的数据处理,包括排序、分组等。

    3). 在完成这些任务的时候,查询需要在不同的地方花费时间,包括网络,CPU计算,生成统计信息和执行计划、锁等待(互斥等待)等操作,尤其是向底层存储引擎检索数据的调用操作,这些调用需要在内存中操作、CPU操作

         和内存不足时导致的IO操作上消耗时间,根据上下文不同,可能会产生大量的上下文切换以及系统调用。

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

    查询性能低下最基本的原因是访问的数据太多。某些查询可能不可避免地需要筛选大量数据,但这并不常见。大部分性能低下的查询都可以通过减少访问的数量的方式进行优化。对于低效查询,可以通过下面两个步骤来分析:

    1). 确认应用程序是否在检索大量超过需要的数据。这通常意味着访问了太多的行,但有时候可能是访问了太多的列。

    2). 确认mysql服务器层是否在分析大量超过需要的数据行。

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

          1).  一些典型案例

                a. 查询不需要的记录:一个常见的错误是常常会误以为MySQL会只返回需要的数据,实际上MySQL却是返回全部结果集在进行计算。最简单有效的解决方法是在这样的查询后面加上LIMIT。

                b. 多表关联时返回全部列

                c. 总是取出全部列:每次看到SELECT * 的时候都需要用怀疑的眼光审视,是不是真的需要返回全部列?取出全部列会让优化器无法完成索引覆盖扫描这类优化,还会为服务器带来额外的网络、IO、内存和

                   CPU的消耗。

               d. 重复查询相同的数据:比较好的方案是,当初次查询的时候将这个数据缓存起来,需要的时候从缓存中取出,这样性能会更好。

    2.2 MySQL是否在扫描额外的记录:

          1). 对于MySQL,最简单的衡量查询开销的三个指标如下:

               a. 响应时间:响应时间是两部分之和:服务时间和排队时间。服务时间是指数据库处理这个查询真正花多长时间。排队时间是指服务器因为等待某些资源而没有真正执行查询的时间--可能是等IO操作完成,也可能

                                 是等待行锁等等。

               b. 扫描的行数和返回的行数:分析查询时,查看该查询扫描的行数是非常有帮助的。这在一定程度上能够说明该查询找到需要的数据的效率高不高。

               c. 扫描的行数和访问类型:在评估查询开销的时候,需要考虑一下从表中找到某一行数据的成本。MySQL有好几种访问方式可以查询并返回一行结果。有些方式可能需要扫描很多行才能返回一行结果,也有些访问

                  方式可能无需扫描就能返回结果。

                  在EXPALIN语句中的type列反应了访问类型。访问类型有很多种,从全表扫描到索引扫描、范围扫描、唯一索引扫描、常数引用等。这里列的这些,速度是从慢到快,扫描的行数是从多到少。你不要记住这

                  些访问类型,但需要明白扫描表、扫描索引、范围访问和单值访问的概念。

          2). 一般MySQL能使用如下三种方式应用WHERE条件,从好到坏依次为:

               a. 在索引中使用WHERE条件来过滤不匹配的记录。这是在存储引擎层完成的。

               b. 使用索引覆盖扫描(在Extra列中出现Using index)来返回记录,直接从索引中过滤不需要的记录并返回命中的结果。这是在MySQL服务器层完成的,但无需再回表查询记录。

               c. 从数据表中返回数据,然后过滤掉不满足条件的记录(在Extra列中出现Using Where)。这在MySQL服务器层完成,MySQL需要先从数据表读取记录然后过滤。

          3). 如果发现查询需要扫描大量的数据但只返回少数的行(使用聚合函数等),那么通常可以尝试下面的技巧去优化它们:

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

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

               c. 重写这个复杂的查询,让MySQL优化器能够以更优的方式执行这个查询。 

 3. 重构查询的方式:有时候,可以将查询转换一种写法让其返回一样的结果,但性能更好。

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

           a. 设计查询的时候一个需要考虑的重要问题是,是否需要将一个复杂的查询分成过个简单的查询。在传统实现中,总是强调需要数据库层完成尽可能多的工作,这样做的逻辑在于以前总是认为网络通信、

               查询解析和优化是一件代价很高的事情。但是这样的想法对于MySQL并不适用,MySQL从设计上让连接和断开连接都很轻量级,在返回一个小的查询结果方面很高效。现代的网络速度比以前要快的多,

               无论是带宽还是延迟。

           b. MySQL内部每秒能够扫描内存中上百万行数据,相比之下,MySQL响应数据给客户端就慢得多了。在其他条件都相同的时候,使用尽可能少的查询当然是更好的。但是有时候,将一个大查询分解成

               多个小查询也是很有必要的。

     3.2 切分查询:删除旧数据是一个很好的例子。定期清除大量数据时,乳沟用一个大的语句一次性删除完成的话,则可能需要一次锁住很多数据、占满整个事务日志、耗尽系统资源、阻塞很多小的但很重要的查询。

           同时需要注意,如果每次删除数据后,都暂停一会再做下一次删除,可以经服务器压力分散到很长的时间段中。

     3.3 分解关联查询:

          分解关联查询的方式重构查询有如下的优势:

          a. 让缓存的效率更高。许多应用程序可以方便地使用缓存单表查询对应的结果集。

          b. 将查询分解后,执行单个查询可以减少锁的竞争。

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

          d. 查询本身效率也可能会有所提升。

          e. 可以减少冗余记录的查询。管理查询中可能需要重复地访问一部分数据。

          f. 更进一步,这样做相当于在应用中实现了哈希关联,而不是使用MySQL的嵌套循环关联。某些场景哈希关联的效率要高很多。

4. 查询执行的基础:

    查询执行的过程:

    1). 客户单发送一条查询给服务器

    2). 服务器检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段。

    3). 服务器端进行SQL解析、预处理,再由优化器生成对应的执行计划。

    4). MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询。

    5). 将结果返回给客户端。 

     

 

以上是关于mysql笔记03 查询性能优化的主要内容,如果未能解决你的问题,请参考以下文章

MYSQL优化 学习笔记

MySQL《高性能MySQL》学习笔记,第四章,Schema与数据类型优化

《高性能MySQL》读书笔记

MySQL查询性能优化

《高性能MySQL》读书笔记之创建高性能的索引

高性能Mysql学习笔记——Mysql体系结构