热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Mysql调优的顺序及面试问题总结

文章目录一、调优相关1.第一步:本地explain线上查询遇到的第一个坑:遇到的第二个坑:2.第二步:覆盖索引3.第三步&#

文章目录

  • 一、调优相关
    • 1.第一步:本地explain+线上查询
      • 遇到的第一个坑:
      • 遇到的第二个坑:
    • 2.第二步:覆盖索引
    • 3.第三步:联合索引
    • 4.第四步:最左匹配原则
    • 5.第五步:索引下推
    • 6.唯一索引普通索引选择难题
    • 7.第七步:前缀索引
    • 8.第八步:条件字段函数操作
    • 9.第九步:防止类型隐式转换
    • 10.第十步:隐式字符编码转换
    • 11.第十一步:flush
  • 二、面试问题
    • 1)B树和B+树的区别,为什么mysql使用B+树?
    • 2)mysql有哪些存储引擎?
    • 3)MyISAM和InnoDB的区别是什么?
    • 4)什么叫回表?
    • 5)什么叫聚簇索引?
    • 6)什么是索引覆盖?怎么实现?
    • 7)谈谈联合索引生效的条件和失效的条件?
    • 8)什么是索引下推?




在这里插入图片描述
一、调优相关

1.第一步:本地explain+线上查询


在开发涉及SQL的业务都会去本地环境跑一遍SQL,用explain去看一下执行计划,看看分析的结果是否符合自己的预期(type是否为eq_ref、ref),用没用到相关的索引(possible_keys和key是不是想要的),然后再去线上环境跑一下看看执行时间(这里只有查询语句,修改语句也无法在线上执行)。
在这里插入图片描述


  • eq_ref :对于前表的每一行,后表只有一行被扫描
  • ref:对于前表的每一行,后表可能有多于一行的数据被扫描

遇到的第一个坑:


因为在MySQL8.0之前我们的数据库是存在缓存这样的情况的,我之前就被坑过,因为存在缓存,我发现我sql怎么执行都是很快,当然第一次其实不快但是我没注意到,以至于上线后因为缓存经常失效,导致rt(Response time)时高时低。


解决方法:SQL NoCache去跑SQL


原因:缓存失效比较频繁的原因就是,只要我们一对表进行更新,那这个表所有的缓存都会被清空,其实我们很少存在不更新的表。


遇到的第二个坑:


  • 统计的行数就是完全对吗?

1)MySQL中数据的单位都是,MySQL又采用了采样统计的方法,采样统计的时候,InnoDB默认会选择N个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。
2)我们数据是一直在变的,所以索引的统计信息也是会变的,会根据一个阈值,重新做统计。


解决方法:analyze table tablename 就可以重新统计索引信息了,所以在实践中,如果你发现explain的结果预估的rows值跟实际情况差距比较大,可以采用这个方法来处理。


  • 索引一定会走到最优索引么?

1)如果走A索引要扫描100行,B所有只要20行,但是他可能选择走A索引
2)一般走错都是因为优化器在选择的时候发现,走A索引没有额外的代价,比如走B索引并不能直接拿到我们的值,还需要回到主键索引才可以拿到,多了一次回表的过程,这个也是会被优化器考虑进去的。


解决方法:还有一个方法就是force index强制走正确的索引,或者优化SQL,最后实在不行,可以新建索引,或者删掉错误的索引。


2.第二步:覆盖索引

1)说明:

可能需要回表这样的操作,那我们怎么能做到不回表呢?在自己的索引上就查到自己想要的,不要去主键索引查了。


  • 如果在我们建立的索引上就已经有我们需要的字段,就不需要回表了,比如在电商里面,我们需要去商品表通过各种信息查询到商品id,id一般都是主键,可能sql类似这样:
    select itemId from itemCenter where size between 1 and 6
    在这里插入图片描述

  • 因为商品id itemId一般都是主键,在size索引上肯定会有我们这个值,这个时候就不需要回主键表去查询id信息了。

  • 由于覆盖索引可以减少树的搜索次数,显著提升查询性能,所以使用覆盖索引是一个常用的性能优化手段。
    (覆盖索引一般针对的是辅助索引,整个査询结果只通过辅助索引就能拿到结果,不需要通过辅助索引树找到主键,再通过主键去主键索引树里获取其它字段值。这个辅助索引可以是组合索引)
    举例传送门
    假设你定义一个联合索引

CREATE INDEX idx_name_age ON user(name,age);

查询名称为 liudehua 的年龄:

mysql> select name, age from user where name = 'liudehua';

上述语句中,查找的字段 name 和 age 都包含在联合索引 idx_name_age 的索引树中,这样的查询就是覆盖索引查询。

3.第三步:联合索引


  • 还是商品表举例,我们需要根据他的名称,去查他的库存,假设这是一个很高频的查询请求,你会怎么建立索引呢?
  • 解决方法:

建立一个,名称和库存的联合索引,这样名称查出来就可以看到库存了,不需要查出id之后去回表再查询库存了,联合索引在我们开发过程中也是常见的,但是并不是可以一直建立的,大家要思考索引占据的空间。


4.第四步:最左匹配原则


最好能利用到现有的SQL最大化利用,像上面的场景,如果利用一个模糊查询 itemname like ’谢白羽%‘,这样还是能利用到这个索引的,而且如果有这样的联合索引,大家也没必要去新建一个商品名称单独的索引了。

指的是联合索引中,优先走最左边列的索引。对于多个字段的联合索引,也同理。如 index(a,b,c) 联合索引,则相当于创建了 a 单列索引,(a,b)联合索引,和(a,b,c)联合索引。

5.第五步:索引下推

select * from itemcenter where name like '谢%' and size=22 and age = 20;

  • 所以这个语句在搜索索引树的时候,只能用 “谢”,找到第一个满足条件的记录ID1,当然,这还不错,总比全表扫描要好。

  • 在MySQL 5.6之前,只能从ID1开始一个个回表,到主键索引上找出数据行,再对比字段值。
    在这里插入图片描述

  • 而MySQL 5.6 引入的索引下推优化(index condition pushdown), 可以在索引遍历过程中,对索引中包含的字段先做判断,直接过滤掉不满足条件的记录,减少回表次数。
    在这里插入图片描述


6.唯一索引普通索引选择难题


  • 当需要更新一个数据页时,如果数据页在内存中就直接更新,而如果这个数据页还没有在内存中的话,在不影响数据一致性的前提下,InooDB会将这些更新操作缓存在change buffer中,这样就不需要从磁盘中读入这个数据页了。

  • 什么条件下可以使用change buffer呢?


要判断表中是否存在这个数据,而这必须要将数据页读入内存才能判断,如果都已经读入到内存了,那直接更新内存会更快,就没必要使用change buffer了。因此,唯一索引的更新就不能使用change buffer,实际上也只有普通索引可以使用。


  • change buffer的大小,可以通过参数innodb_change_buffer_max_size来动态设置,这个参数设置为50的时候,表示change buffer的大小最多只能占用buffer pool的50%。将数据从磁盘读入内存涉及随机IO的访问,是数据库里面成本最高的操作之一.change buffer因为减少了随机磁盘访问,所以对更新性能的提升是会很明显的。

7.第七步:前缀索引


  • 我们存在邮箱作为用户名的情况,每个人的邮箱都是不一样的,那我们是不是可以在邮箱上建立索引,但是邮箱这么长,我们怎么去建立索引呢?
  • MySQL是支持前缀索引的,也就是说,你可以定义字符串的一部分作为索引。默认地,如果你创建索引的语句不指定前缀长度,那么索引就会包含整个字符串。

但是:

但是前缀索引,即使你的联合索引已经包涵了相关信息,他还是会回表,因为他不确定你到底是不是一个完整的信息,就算你是www.aobing@mogu.com一个完整的邮箱去查询,他还是不知道你是否是完整的,所以他需要回表去判断一下。

解决方法:

你可以substring()函数截取掉前面的,然后建立索引。hash,把字段hash为另外一个字段存起来,每次校验hash就好了,hash的索引也不大。


8.第八步:条件字段函数操作


  • 对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能。
  • 这个时候大家可以用一些取巧的方法,比如 select * from tradelog where id + 1 = 10000 就走不上索引,select * from tradelog where id = 9999就可以。

9.第九步:防止类型隐式转换

select * from t where id = 1

  • 如果id是字符类型的,1是数字类型的,你用explain会发现走了全表扫描,根本用不上索引,为啥呢?

  • 因为MySQL底层会对你的比较进行转换,相当于加了 CAST( id AS signed int) 这样的一个函数,上面说过函数会导致走不上索引。


10.第十步:隐式字符编码转换


  • 还是一样的问题,如果两个表的字符集不一样,一个是utf8mb4,一个是utf8,因为utf8mb4是utf8的超集,所以一旦两个字符比较,就会转换为utf8mb4再比较。
  • 转换的过程相当于加了CONVERT(id USING utf8mb4)函数,那又回到上面的问题了,用到函数就用不上索引了。
  • 还有大家一会可能会遇到mysql突然卡顿的情况,那可能是MySQLflush了。

11.第十一步:flush


  • redo log大家都知道,也就是我们对数据库操作的日志,他是在内存中的,每次操作一旦写了redo log就会立马返回结果,但是这个redo log总会找个时间去更新到磁盘,这个操作就是flush。

  • Innodb刷脏页控制策略,我们每个电脑主机的io能力是不一样的,你要正确地告诉InnoDB所在主机的IO能力,这样InnoDB才能知道需要全力刷脏页的时候,可以刷多快。

  • 这就要用到innodb_io_capacity这个参数了,它会告诉InnoDB你的磁盘能力,这个值建议设置成磁盘的IOPS,磁盘的IOPS可以通过fio这个工具来测试。正确地设置innodb_io_capacity参数,可以有效的解决这个问题。

  • 补充:这中间有个有意思的点,刷脏页的时候,旁边如果也是脏页,会一起刷掉的,并且如果周围还有脏页,这个连带责任制会一直蔓延,这种情况其实在机械硬盘时代比较好,一次IO就解决了所有问题,

在这里插入图片描述

二、面试问题

1)B树和B+树的区别,为什么mysql使用B+树?

1)B树:
①一个节点有多个元素
②整个树都是排好序的
2)B+树:
①叶子节点是有指针的
②一个节点有多个元素
(用这种存储结构来存储大量数据的情况下呢,它的整体高度相比二叉树来说比较低,而对于数据库来说,所有的数据存储必然是存储在磁盘上的而磁盘io的效率事件上是很低的,特别是随机磁盘的一个情况下效率更低,所以树的高度决定磁盘io一个次数,磁盘io次数越少,那么对性能的提升就会越大,采用b树作为索引存储结构的原因,)
③整个树都是排好序的
③非叶子节点在叶子节点的元素都冗余了一份
在这里插入图片描述

2)mysql有哪些存储引擎?

InnoDB是mysql默认事物型引擎,也是最广泛的存储引擎,被设计来处理大量短期事务
MyISAM是5.1及之前版本的默认存储引擎,但是不支持事务和行级锁,且崩溃后无法安全恢复。同时MyISAM对表加锁,很容易因为表锁的问题导致典型的性能问题。
Memory引擎:至少比MyISAM表要快一个数量级,数据文件是存储在内存中,查找和映射比较快。表结构在重启后还会保留,但是数据会丢失。
Archive引擎:只支持INSERT和SELECT操作,会缓存所有的写并利用zlib对插入的行进行压缩,所以比MyISAM表的磁盘IO更少。但是每次SELECT查询都需要执行全表扫描,所以一般是用于日志或数据采集类存储
CSV引擎:将普通的CSV文件作为MYSQL的表来处理,但这个表不支持索引,但是可以作为数据交换的机制

3)MyISAM和InnoDB的区别是什么?

①InnoDB支持事务,MyISAM不支持事务
②InnoDB可以包含外键,但是MyISAM不支持
③InnoDB是聚簇索引,MyISAM是非聚簇索引
InnoDB使用辅助索引的时候,如果主键很大,那么其他索引也会很大,因为辅助索引需要两次查询,他存的是主键的信息,然后再根据主键去查询数据
④InnoDB不保存行数,数表行时是全表扫描
⑤InnoDB最小锁粒度是行锁,MyISAM最小锁粒度是表锁

4)什么叫回表?

一次性select不能拿到所有列的数据,还需要到表中再去查找列的数据,就叫回表

5)什么叫聚簇索引?

比如说以主键建立的B+树,叶子节点存储的是对应行的数据,而不是指向另外一块内存(该内存存储对应行数据)的指针,存指针叫做非聚簇索引(或叫辅助索引)

6)什么是索引覆盖?怎么实现?

定义:执行某个查询语句,在一棵索引树上就能获取SQL所需的所有列数据,无需回表
怎么实现:将查询的字段建立到联合索引里面去

7)谈谈联合索引生效的条件和失效的条件?

1、创建联合索引时应仔细考虑列的顺序(知道姓和名更为有用)
2、避免索引失效条件:
①不在索引列上做任何操作,包括不限于计算、函数、自动或手动类型转换
②存储引擎不能使用索引范围条件右侧的列(左侧优先)
③尽量使用索引覆盖(索引和查询列一致)
④mysql在使用(!&#61;,>,<)的时候无法使用索引
⑤is null &#xff0c;is not null也无法使用索引
⑥like以通配符开头&#xff0c;即’%ABC’

8&#xff09;什么是索引下推&#xff1f;

根据条件查询的过程中&#xff0c;再返回server之前就根据比如说联合索引查询的条件过滤了一部分数据&#xff0c;这样在返回数据库server层的时候就减少了回表的次数&#xff08;5.6及5.6以上版本&#xff09;
传送门


推荐阅读
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • Linux如何安装Mongodb的详细步骤和注意事项
    本文介绍了Linux如何安装Mongodb的详细步骤和注意事项,同时介绍了Mongodb的特点和优势。Mongodb是一个开源的数据库,适用于各种规模的企业和各类应用程序。它具有灵活的数据模式和高性能的数据读写操作,能够提高企业的敏捷性和可扩展性。文章还提供了Mongodb的下载安装包地址。 ... [详细]
author-avatar
liuluoyu
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有