Mysql高级调优篇——第三章:Sql实战调优场景剖析(上)

        上几个章节我们讲述了很多硬核的知识,那本章开始我们正式进入Sql实战过程!!

1、热身Case

        回顾上节讲的Explain知识点,我们简单做个回顾,来个热身的Case:

        看下面的Sql执行是如何的,请列出步骤!

        很明显先看id,id依次递增,谁最大谁先执行:

        所以先执行id=4,执行t2表:select name, id from t2

        再执行id=3,t1表的查询:select id, name from t1 where other column = ''

        再执行id=2,t3表的查询:select id from t3

        再执行id=1,这个表是由id=3这个表衍生的表,查询的结果来自id=3的结果,且table被标记为derived3,select_type为primary表示外层查询。

        最后执行id=NULL,代表从union的临时表读取行的阶段,table为<union1,4>表示用id=1和id=4的select结果进行union操作!

2、索引单表优化案例剖析

        表的结构在我之前的一篇文章里,附上链接可以自行去Copy:
Mysql高级调优篇表补充——建表SQLhttps://blog.csdn.net/qq_31821733/article/details/120886389?spm=1001.2014.3001.5501

        新建article表:

2.1、查询category_id为1且comments大于1的情况下,views最多的article_id

        Sql:select id, author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;

        执行计划后,会发现多一个列filtered,这个是5.7版本后添加的,意思是:

        指返回结果的行占需要读到的行(rows列的值)的百分比,比如我返回了10行,但是我需要读1000行,这个比例就是10%,filtered的数值其实越高,表示通过索引直接返回的行很多,数值较低时,一般出现在type=ALL或者index的情况。

         分析下这个执行计划,type=ALL全表扫,而且产生了filesort,功能完成了,但是作为开发一定要考虑到你的sql性能,这个是你的谈资!

        看下索引:目前只有一个主键id默认主键索引。

        因为我们sql的where条件后有三个字段,首先想到加的复合索引:

        我也不知道对不对,但是先这么尝试,然后看看执行计划:

        发现走了索引了,但是发现走到了filesort,这样还不行;

        说明这个索引不起作用吗?那假设我们把sql调整为comments = 1再看看执行计划

        很明显,filesort没有了,type一下从range变成了ref,这个情况是最好的,但是合不合理?业务都变了。

         分析下:我们建立的索引是ccv,上面的sql是范围查comments,而下面的是指定常量const,肯定是常量更精确,所以在Mysql中,索引中出现了范围查找,后面就失效,comments出现了范围,索引在找的时候,发现comments无法直接定位到,影响了order by views的索引排序,进而出现了filesort。不好意思,你让我去2楼找进3口的入口,我一个一个找,这个时候我无法走到索引,自然找不到我就不能按照你的索引顺序走到3楼了。Mysql做不到时,内部自己产生了个排序,出现了filesort。总结一句话:

        范围索引全失效

        结论是:type变成了range,这是可以忍受的,但是Extra里出现了filesort是无法接受的,但是我们建立了索引为什么没有用,这是因为按照Mysql的BTREE工作原理,先排序category_id,如果遇到相同的,再排序comments,如果遇到相同的,再排序views,当comments位置处于联合(复合)索引的中间位置时,Mysql无法对范围(range)后面的字段进行索引排序,从而后面的字段索引失效!

        刚刚建立的索引对于当前的需求,并不是最合适,那么怎么优化呢?

        我们先删除刚刚的索引:

        既然范围之后索引失效,那么我们能不能绕过去?直接新建category_id, views的复合索引。执行计划告诉我们,这个索引加的很合适!

 3、索引两表优化案例剖析

        两表的情况在开发中也很常见,这里我新建book表和class表:

        这两个表无需关心含义,我们看具体Sql:

        Sql1:select  * from class left join book on class.card = book.card;

        看到这个sql应该立马想到我之前画的图,很明显取的是class的全部,加上book不满足的部分;

         执行计划跑下看:明显这个type为ALL,索引也没有加

        问题来了,索引加哪边?是加class.card还是book.card?

        我们都试试,先添加右边book表的索引:

        执行计划走下:book的很明显的改变,type变成了ref

         此时我把book表的索引删掉,而建立class左表的索引看看执行计划:明显,加了class表的索引后,发现type是index,并且rows20行记录,全索引扫描,性能不会有刚刚的好!

        同样的sql,同样的索引列,左连接的时候,加的索引所在的表不同,效果不同;

        总结一句话:左连接相反加!

        结论:上面出现效果不同,这个是由左连接的特性决定的,left join 条件用于确定如何从右边搜索行,而左边一定是都有的; 左边全有,确定核心的点在于确定如何从右表中搜索数据行,右边是关键点,要加索引!所以左连接索引加在右表上,同理,右连接也是相反加!

        有没有人好奇,如果两个索引都建呢会是什么样?我们尝试下加上看看:

        现在book和class表上的card字段都加了索引,效果比上面两个都好!

        在具体工作中我们还是要具体分析!

4、索引三表优化案例剖析

        讲完两个表,我们讲下三表怎么优化

        在基于上面两个表book和class的前提下,我们新增加一个表,叫做phone表,字段也差不多:

         把book表和class表的索引都清除掉;

        假设我有这么一个sql:

        select * from class left join book on class.card = book.card left join phone on book.card = phone.card; 看下结果,两表的连接基础打牢固,其实三表的是一样的。

         此时三个表都没有索引:我们走下执行计划后发现,Extra字段多了Using join buffer;首先join buffer意思是使用了连接缓存,在5.7之后,Mysql对表和表之间的连接,做了优化缓存,实际上在A left join B的过程,Mysql会更在意B的表往A中相同的部分,所以类似一个for循环,最外层for A,内层是for B,找到B中的每一行满足A行的记录,因为是要A的全部,所以最外层一定是A,然后合并行,最后输出;而在3表中,等于3个for循环。

        其中其实发现有个Block Nested-Loop Join——BNL算法,这个算法将外层循环的行/结果集存入join buffer, 内层循环的每一行与整个buffer中的记录做比较,从而减少内层循环的次数。所以最外层的表是class,先for整个class,然后放在join buffer里,接下来循环内表的时候,直接取buffer的行去比对,减少对磁盘的IO。

        但是整个type=ALL,rows都是20,全表扫,这是我们无法接受的。

         那么三张表怎么加索引呢?可以想想,左连接建右表上,那么这个是不是说class左表,建立索引在book和phone上?试试!

        走下执行计划看看:很明显,改善很多!

        那么很明显这个原则也成立,总结下:

        尽可能减少join语句中的NestedLoop循环总次数,永远用小结果集驱动大的结果集,这里的例子,就是左表尽量数据小于右表,外层for的次数就减少了,IO次数也会降低。

        优先优化NestedLoop的内层循环;

        保证join语句中被驱动表上的字段已经被索引;

        当无法保证被驱动表的join字段被索引且内存资源充足的前提下,不要吝啬JoinBuffer的设置值。JoinBuffer在my.cnf中,由DBA运维着。

        其实你可以试试,如果class表加了索引,效果会比右连接稍微好点,哈哈

         但是这个不一定可行,具体数据场景具体分析!

        本章讲了优化索引实例,下一章节继续索引其他场景实战!!

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
MySQL高级调优是针对MySQL数据库性能优化的一系列操作和技术手段,旨在提升数据库的响应速度、并发处理能力和稳定性。 首先,在硬件层面,可以通过增加服务器的内存、磁盘带宽和处理器等硬件资源来提升MySQL的性能。同时,可以使用RAID技术提供更高的磁盘I/O性能,并进行适当的磁盘配置和分区。 其次,在数据库设计层面,要合理设计数据库表结构,避免数据冗余和分散索引等问题。使用合适的数据类型和长度,以减小数据存储的空间,提高查询效率。合理划分并使用表空间,提升磁盘IO性能。 在MySQL配置方面,可以根据具体需求和硬件环境,调整参数设置来提高性能,如innodb_buffer_pool_size、innodb_log_file_size、max_connections等参数。同时,通过开启慢查询日志、查询缓存和二进制日志等功能来分析和优化SQL查询性能。 此外,索引的正确使用对MySQL的性能至关重要。通过合理地创建索引和删除不必要的索引,可以极大地提升查询效率。需要注意的是,索引不宜过多,否则会增加写入操作的负担。 在查询语句的编写中,应尽量避免使用SELECT *,而是明确指定需要的字段。同时,合理利用limit、join查询和子查询等功能,减小查询数据集大小和复杂度。 最后,通过监控与调优工具,如MySQL自带的slow query log和performance_schema,可以实时监控和分析数据库的性能瓶颈,及时调整配置和优化SQL查询语句。 综上所述,MySQL高级调优是一个综合性的工作,需要从多个方面进行优化。在硬件、设计、配置、索引、SQL编写和监控等各方面进行细致而合理的调整,才能有效提升MySQL数据库的性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风清扬逍遥子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值