MySQL 查询优化实战|学习笔记(三)

简介: 快速学习 MySQL 查询优化实战

开发者学堂课程【MySQL 实战进阶MySQL 查询优化实战】学习笔记,与课程紧密联系,让用户快速学习知识

课程地址:https://developer.aliyun.com/learning/course/83/detail/1308


MySQL 查询优化实战


六、常规的优化策略

1、第一块是对排序的优化,对于排序的优化先看对 order by 的查询分两种情况,首先是第一种 using index,这个是针对查询优化器的两种行为去分的。Using indexMySQL 直接通过索引返回有序记录,不需要额外的排序操作,操作效率较高。第二种叫 using filesort,无法只通过索引获取有序结果集,需要额外的排序,某些特殊情况下,会出现临时表排序的情况。对于 order by 排序优化的目标很简单,就是尽量通过索引来避免额外的排序,减少 CPU 资源的消耗。

2、对于这一方面一般有三个方法去做,第一个是 where 条件和 order by 使用相同的索引;第二个是 order by 的顺序和索引顺序尽量相同;最后一个也比较重要,就是 order by 的字段最好同为升序或降序。因为 B+Tree 索引有多个字段的话,不同的字段之间,如果是不同升或者不同降,本质上就是 B+Tree 索引的排序是不可能出现不同的字段,前面是升序,后面是降序这样的一个排序情况。

:where 条件中的过滤字段为覆盖索引的前缀列,而order by字段是第二个索引列时,只有 where 条件是 const 匹配时,才可以通过索引消除护序,而between…and >?这种 range 匹配都无法避免 filesort 操作

2、当没有办法避免排序操作时,优化的思路就是让排序的操作更快。排序的操作更快就提到了排序算法,包括两次扫描算法和一次扫描算法。它们本质的区别是两次扫描算法分阶段去完成,它的目的是为了更加节约内存空间。从本质上看,一次扫描算法效率更高,但是它会消耗一些内存。这里需要注意到的一点就是需要排序的字段总长度越小,越趋向于第二种扫描算法,

MySQL通过 max_length_for_sort_data 参数的值来进行参考选择。这样也可以给我们一些有帮助的建议,对于 select 语句提升排序的操作,一般可行的优化策略主要是三点。

第一点适当调大 max_length_for_sort_data 这个参数的值,这个参数的目的是为了让优化器更倾向于选择第二种扫描算法。刚才也提到了关于排序的两种算法,想要提排序训操作的话,一个核心的思想就是通过空间换时间,一次扫描算法虽然会消耗更多的内存空间,但是它排序的速度会更快。第二点,只使用必要的字段,不要使用 select*的写法,因为目的是为了让字段排序的总长度不要过长。第三点可以适当加大sort_buffer_size 这个参数的值,避免磁盘排序的出现。

4、第二个是对于 subquery 子查询,对于子查询会在大部分情况下都会利用到临时表,一般情况下需要尽量避免;可以使用效率更高的 join 查询来代替。对于临时表一般的优化策略可以做等价改写,这种策略在 MySQL 查询优化器里面有一个专业的词叫做反嵌套。在 MySQL 里面查询优化器也可以做一些简单的子查询的反嵌套的操作,但是在绝大部分情况下,还是需要人为的干预。看下面的 SQL 语句用 not in 的方式,后面是在一个子查询里面执行 select 语句。

对于这个 SQL 语句思路很清晰,直接把 not in 该写成 left join

MySQL 里面,join 的效率比子查询的效率还是高一些的。

5、第三种是 limit,分页查询的优化。分页查询本质上就是将过多的结果在有限的界面上分好多页来显示,它的实质是每次查询只返回有限行,翻页一次执行一次。对于分页查询的目标,第一个是消除排序,分页查询当中一般 limit 的操作,在绝大部分情况下都会跟 order by 排序,是跟他关联的,所以在这种场景下第一步需要消除排序的。

第二点是避免扫描到大量不需要的记录,比如说有一个 SQL 场景,

film_id 是主键,这里列的 SQL语句 limit 1000020,对于这个 SQL 语句,通常情况下它自己执行的话,需要扫描到 MySQL 里面前10020条数据,真正返回客户端的时候把前10001之前的数据全部去掉。为什么要优化分页查询?就是在做分页的时候,这种情况前面的一万条记录会造成额外的数据扫描的代价。

6、对于分页查询的策略,第一个提到了覆盖索引,

在某些比较特殊的场景,就是 where 条件和 select 返回的字段都特别少的情况下,就可以直接通过索引覆盖的方式,可以直接从索引当中获取想要的数据比如说像本次的 SQLorder by title,前面是select film_iddescription

对于这个 SQL 只要给 title description 建一个复合索引,film_id 本身是做的示例的主键。建了这个索引之后可以看到这个 sql select,跟后面排序的字段都被索引所覆盖。通过覆盖索引最大的一个好处是需要的记录可以直接从索引中获取,效率最高;仅适合查询字段较少的情况。

image.png

7、下面是第二种优化策略,通过改写的这种方式做优化。

这个本身上也是通过覆盖索引的原则,通过这种 join 的方式去改写的前提,可以看到在 join 后面加了一个子查询。先加这个子查询是因为这个里面是一个 select 语句,其实是把分页的查询分为两步去做,第一步就是通过里面的查询先取出所需要的20条记录的主键 id;第二步就是通过跟主表做关联,然后再取到想要的20条数据。本质上也是通过覆盖索引的方式做优化,对于查询的字段,一般情况下不会像场景一,它查询的、所返回的字段特别少。通常情况下 where 条件 select 返回字段可能都会有很多,不可能给所有的字段都建复合索引,这样的情况下,通常优化改写的策略就是通过 join 改写的方式,先通过覆盖索引取出主键 ID,然后再通过关联。

8、下面的场景是 or and 条件的优化,首先看一下 or and 的区别。or 是并集,and 是交集,在 MySQL 里面需要注意一点,交集的查询条件。这里可以看到 condition a condition b,对于交集的话就是其中有一个条件,可以利用到选择性比较好的索引,sql语句本身效率就没有太大的问题。

 image.png

它和 or 最大的一个区别是or 条件在处理的时候会把它视为 UNION,所以 or 可以看到condition a condition b。在一个查询语句当中通过 or 把他去联系起来,相对于条件 a 和条件 b 是两个 SQL 语句看待,所以对于 or 的话 condition a condition b他们都需要通过对应的索引做优化。而不是像 and 一样,有两个条件,只要有一个条件有过滤性比较好的索引就可以了。

SELECT 优化-or/and condition

·and 结果集为关键字前后过滤结果的交集·or结果集为关键字前后分别查询的并集

·and 条件可以在前一个条件过滤基础上过滤

·or 条件被处理为 UNION,相当于两个单独条件的查询·复合索引对于or条件相当于一个单列索引

处理策略:

and 子句多个条件中拥有一个过滤性较高的索引即可

or 条件前后字段均要创建索引

√为最常用的and组合条件创建复合索引

9、下面看关于 join 的优化,在 MySQL 里面,先看一个比较典型的算法,Nested-Loop Join 的算法。对于这个算法简单点来说,就是一个循环,t1t2t3 这三张表去做 join 的话,t1 表首先去扫描匹配到的行,通过 t1 当中的每一行,再根据 t1 t2 的关联条件,再去扫描t2 当中匹配到的每一行,在 t2 t3 的时候也是这样。

Join 的本质就是嵌套循环的过程,对于嵌套循环需要注意两点,第一点,优化的核心跟关联的字段要添加索引,添加索引的目的是为了让每一层的内部循环仅仅获取需要关心的数据就可以了。有一个隐身算法叫 Block Nested-Loop,看下图

image.png

下面是 Block Nested-Loop,在MySQL里面有一个特性叫 join buffer

简单点说,当两张表的关联不能通过索引去做关联条件的匹配的话,在做join的时候就会产生 join buffer。当 SQL join 语句他的执行计划里面出现 Block Nested-Loop 的时候,在这样情况下就需要花心思去看,看关联条件是不是没有索引,或者因为一些其他的原因而导致关联的匹配没有通过索引。因为当 sql 语句出现 的时候,SQL 的效率会大幅下降。第二点是小表驱动原则,就是让最外层的结果结尽量小,这个目的是为了减少循环的次数。

10、关联字段索引的必要性,看如下案例

image.png

对于特别简单的select count * 的语句,语句非常简单,就是两张表的一个 join 关联。下面看 SQL 语句的执行计划的时候,已经出现了 using join buffer,就是前面所说的 Block Nested Loop,可以看到通过 b 表去访问 a表的时候,可以看到rows 127042,也就是整个访问的过程代价非常大。对于这种产品优化的策略也特别简单,

image.png

直接给 a 表添加一个索引,给关联的条件添加一个索引。后面可以看到通过 b 表再去访问 a表的时候,执行计划里面的 key 就使用到了刚才添加的索引,rows 也从127042下降到了125。执行效率前面接近两分钟,优化后是0.31秒。

11、第二个是小表驱动原则,

image.png

首先做了一个事情是忽略 b 表的索引,使 b 表作为驱动表。先看执行计划,这里是 select count * 的语句,加了一个忽略索引的 hence。这样做的目的是为了产生下面的行为,在执行计划里面是通过 b 表做驱动表,b 表做驱动表的时候可以看 rows 4000×125,执行的成本是0.31秒。可以通过添加 hence 的方式控制优化器的行为,

image.png

刚才是忽略了b 表的索引,这里在忽略 a 表的索引,

image.png

这个时候就会发现 a 表成了驱动表,b 表成了被驱动。这个时候再看rows,它变成了127042×4。这有一个很本质的区别就是,后面这一种优化器扫描的方式,比前面的方式成本是提升了不少的。虽然在这两个 SQL 语句做关联的时候,不管是通过 a 表还是 b 表去做驱动,最后在通过关联的时候,其实都是通过了索引,但是因为他们驱动表的大小问题导致最终 rows 行数的代价是不一样的,后面这一种写法产生的时间是0.53秒,这比前面差不多慢了一倍。

12、最后一种是关于 insert 插入的优化,关于插入的优化策略主要是两个,第一个是为了减少网络的消耗,主要的策略是减少跟 MySQL SQl 交互的次数。有些时候可能会有些开发人员会提交大批量的插入语句,如果拷十万条,每一条都是 insert into 这样的语句,

对于这种单条的插入语句可以做一些适当的合并。在下面一条 insert into 语句后面可以接多个值,

对刚才所说的场景做一些适当的插入的合并,这种提升的效果一般是比较明显的。因为它减少了 SQL端交互的次数,主要是从网络的开销上面做的优化。第二种策略可以通过文本装载的方式,通过 LOAD DATA INFILE 句式,通过文本装载数据的方式,通常情况下,通过 load data in fact 方式比直接插入 insert 语句快20倍。

 

七、总结

1、本课程对于各个优化的环节基本上讲完了,最后做一个小结。关于 MySQL 查询优化第一块,优化的目的是为了让资源发挥价值,SQL 和索引是调优的关键,往往可以起到四两拨千斤的效果。可能简单的加一个索引或一个 SQL 语句,做一个简单的改写,可以让整个系统大幅提升它的性能。

2、第二块关于优化流程和思路上,第一个需要充分了解数据库里的核心指标,并且需要构建相对完备的监控体系,这是优化工作的前提。因为这样做的目的是为了获取整个数据库性能的一些数据。第二个是 SQL 优化的原则是减少数据的访问及计算,常用的优化方法主要是调整索引、改写 SQL 以及干预执行计划。

3、第三块是关于 MySQL 内部核心的原理,以及相应的行为相关的内容,第一个innodb 的表示典型的 IOT,数据本身是 B+Tree 索引的叶结点,第二个是扫描二级索引可以直接获取 select 查询数据,或者是返回主键ID,再获取真正的数据。最后,关于优化器需要注意的一点是优化器是数据库的大脑,需要做优化工作的话,要先了解优化器,并且在实际的调优过程中要观测以及在适当的时候干预 MySQL 的行为。关于 MySQL 查询优化的课程到此结束。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
7月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
缓存 关系型数据库 MySQL
MySQL索引策略与查询性能调优实战
在实际应用中,需要根据具体的业务需求和查询模式,综合运用索引策略和查询性能调优方法,不断地测试和优化,以提高MySQL数据库的查询性能。
631 66
|
SQL 关系型数据库 MySQL
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
MySQL慢查询优化、索引优化,是必知必备,大厂面试高频,本文深入详解,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验分享。
大厂面试官:聊下 MySQL 慢查询优化、索引优化?
|
缓存 关系型数据库 MySQL
MySQL执行计划选择策略:揭秘查询优化的艺术
【10月更文挑战第15天】 在数据库性能优化中,选择最优的执行计划是提升查询效率的关键。MySQL作为一个强大的关系型数据库管理系统,提供了复杂的查询优化器来生成执行计划。本文将深入探讨如何选择合适的执行计划,以及为什么某些计划更优。
381 2
|
11月前
|
存储 关系型数据库 MySQL
MySQL索引学习笔记
本文深入探讨了MySQL数据库中慢查询分析的关键概念和技术手段。
733 81
|
前端开发 关系型数据库 MySQL
PHP与MySQL动态网站开发实战指南####
【10月更文挑战第21天】 本文将深入浅出地探讨如何使用PHP与MySQL构建一个动态网站,从环境搭建到项目部署,全程实战演示。无论你是编程新手还是希望巩固Web开发技能的老手,都能在这篇文章中找到实用的技巧和启发。我们将一起探索如何通过PHP处理用户请求,利用MySQL存储数据,并最终呈现动态内容给用户,打造属于自己的在线平台。 ####
555 0
|
7月前
|
缓存 JSON 关系型数据库
MySQL 查询优化分析 - 常用分析方法
本文介绍了MySQL查询优化分析的常用方法EXPLAIN、Optimizer Trace、Profiling和常用监控指标。
|
11月前
|
SQL 存储 关系型数据库
MySQL秘籍之索引与查询优化实战指南
最左前缀原则。不冗余原则。最大选择性原则。所谓前缀索引,说白了就是对文本的前几个字符建立索引(具体是几个字符在建立索引时去指定),比如以产品名称的前 10 位来建索引,这样建立起来的索引更小,查询效率更快!
391 22
 MySQL秘籍之索引与查询优化实战指南
|
SQL 关系型数据库 MySQL
MySQL慢查询优化、索引优化、以及表等优化详解
本文详细介绍了MySQL优化方案,包括索引优化、SQL慢查询优化和数据库表优化,帮助提升数据库性能。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
MySQL慢查询优化、索引优化、以及表等优化详解
|
安全 关系型数据库 MySQL
PHP与MySQL动态网站开发实战指南####
——深入探索LAMP栈下的高效数据交互与处理技巧 ####

推荐镜像

更多