7.性能分析和索引优化
sql执行时间长,性能下降的原因推测:
1.查询语句写的不好
2.索引失效
索引分为:
1.单值索引
create index idx_user_name on user(name)
2.多值索引
create index idx_user_nameEmail on user(name,email)
3.关联查询太多的join(设计缺陷或者不得已的请求)
4.服务器调优及各个参数设置(缓存、线程数等)
sql的执行顺序
执行顺序鱼骨图如下:
7种join
索引
Mysql官方对索引的定义是:索引(Index)是帮助mysql搞笑获取数据的数据结构
索引本质:是一种数据结构
可以简单的理解为:索引是排好序的快速查找数据结构
一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在硬盘上
我们平时说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉树)结构组织的索引,其中包含了聚集索引,次要索引,复合索引,前缀索引,唯一索引
默认都是使用B+数索引,统称为索引
索引的优劣势:
1.优势
提高数据检索效率,降低数据库的io成本
通过索引对数据进行排序,降低数据排序的成本,降低了CPU的消耗
2.劣势
1.实际上索引也是一张表,该表保存了主键和索引字段,并执行实体表的记录,所以索引列也是要占用空间的
2.虽然索引大大的提高了查询效率,同时也会降低更新表的速度,如对表进行INSERT\UPDATE\DELETE
3.因为更新表结构是,mysql不仅要保存数据还要保存一下索引文件每次更新添加了索引的字段,都会调整因为更新所带来的键值变化后的索引信息
索引分类:
1.单值索引:
一个索引值包含单个列,一个表可以有多个单列索引
2.唯一索引
索引列的值必须唯一,但允许有空值
3.复合索引
即一个索引包含多个列
常用命令:
1.创建索引
CREATE INDEX 索引名称 ON 表名 (字段,字段):一个字段就是单值索引,多个字段就是多值索引
ALTER 表名 ADD INDEX 索引名称 ON (字段,字段)
1.1给表添加一个主键,这就意味着索引值必须唯一,且不能为null
ALTER TABLE 表名 ADD PRIMARY KEY(id字段);
1.2该条语句创建的索引值必须唯一(除了NULL外,null可能会出现多次)
ALTER TABLE 表名 ADD UNIQUE 索引名(字段)
1.3添加普通索引,索引值可以出现多次
ALTER TABLE 表名 ADD INDEX 索引名(字段)添加普通索引
1.4指定索引为FULLTEXT,用于全文索引
ALTER TABLE 表名 ADD FULLTEXT 索引名称(字段名)
2.删除索引:
DROP INDEX 索引名称 ON 表名
3.查看索引:
SHOW INDEX FROM 表名
mysql索引结构:
1.BTree索引
2.Hash索引
3.full-text全文索引
4.R-Tree索引
B-TREE的逻辑图如下:

上述图便是b+数的逻辑示意图:
一个b+树,粉红色地区为一个磁盘块,每个磁盘块都包含了数据项和指针(p1,p2,p3)
非叶子节点是不存储真实的数据,只存储指引搜索方向的数据项,如17,35并不真实存在于数据表中
查找过程:
如果查找的数据是29,
1.首先会将磁盘块1加载到内存,此时发生一次IO,在内存中利用二分法查找确定29在17和35之间,锁定磁盘1的p2指针
2.通过磁盘1的p2指针将磁盘3加载到内存中,发生第二次IO,29在26和30之间,锁定磁盘3的p2指针
3.通过指针加载到次磁盘8到内存,发生第三次IO,同时通过二分法查找到29,查询结束,总计三次IO
真实情况:
3层的B+树可以表示上百万的数据,如果上百万的数据查找只需要三次IO,性能提升将是巨大的,如果没有索引,每个数据项都要进行一次IO,那么总共需要上百次的IO,显然成本是非常的高
哪些情况下创建索引:
1.创建索引的情况:
1.主键自动创建唯一索引
2.频繁作为查找条件的字段应该创建索引
3.查询中于其他表关联的字段,外键关系创建索引
4.频繁更新的字段不适合创建索引:因为每次更新不仅是更新了记录还会更新索引信息
5.where条件中用不到的字段不要创建索引
6.单键/组合索引的选择问题:在高并发下倾向于创建组合索引
7.查询中排序字段,排序字段若通过索引去访问会大大的提高排序速度
8.查询中统计或者分组字段
2.不创建索引的情况:
1.表记录太少
2.经常增删改查的表:因为更新表结构是,mysql不仅要保存数据还要保存一下索引文件每次更新添加了索引的字段,都会调整因为更新所带来的键值变化后的索引信息
3.数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的表创建索引
注意:如果某个数据列包含了很多重复的内容,为他创建索引就没有太大的实际效果
性能分析:Explain
mysql常见的瓶颈:
1.CPU:CPU在饱和的时候一般发生在数据装入内存或者从磁盘读取数据的时候
2.IO:磁盘I/O瓶颈发生在状图数据远远大于内存容量的时候
3.服务器硬件的性能瓶颈:使用top,free,iostat和vmstat来查看系统的性能状态
Explain:
使用EXPLAIN关键字可以模拟mysql优化器执行sql查询语句,从而知道Mysql是如何处理你的sql语句的,
分析你的查询语句或者表结构的性能瓶颈
1.使用
explain +sql语句;
如原来:select * from user;
现:explain select * from user;
2.功能:
1.表的读取顺序
2.数据读取操作的操作类型
3.哪些索引可以使用
4.哪些所以被实际使用
5.表之间的引用
6.每张表有多少行可以被优化器查询
explain查询出的字段解释:
1.id
select查询的序列号,包含一组数字,表示查询中执行select子句或者操作表的顺序
三种情况:
1.id相同:执行顺序由上而下
2.id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
3.id如果相同,可以认为是一组,从上而下顺序执行
在所有组中,id值越大,优先级越高,越先执行
2.第二个字段:select_type
有以下几种可能:
1.SIMPLE:简单的select查询,查询中不包含子查询或者UNION
2.PRIMARY:查询中若包含任何复杂的子部分,最外层查询会被标记为PRIMARY
3.SUBQUERY:在select或者WHERE列表中包含了子查询
4.DERIVED:在FROM列表中包含了子查询会别标记为DERIVED(衍生),MYSQL会递归执行这些子查询,把结果放在临时表中
5.UNION:若第二个select初始在UNION之后,则会被标记为UNION,若UNION包含在FROM子句的子查询中,外层select会被标记为:DERIVED
6.UNION RESULT:从UNION表获取结果的select
3.type字段:
有以下几种可能:
1.ALL
2.index
3.range
4.ref
5.eq_ref
6.const,system
7.NULL
从最好到最差的依次是:
system>const>eq_ref>ref>range>index>ALL
一般来说,得保障查询至少达到range级别,最好可以达到ref级别
1.system:表中只有一行记录(等于系统表),这是const(常量)类型的特列,平时不会出现,这个也可以忽略
2.const:表示通过索引依次就可以找到,const用于比较primary kye或者unique索引,因为值匹配一行数据,所以很快
如将主见置于where列表中,mysql就能将该查询转换为一个常量
3.eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常见于主见或者唯一索引扫描.
4.ref:非唯一性索引扫描,返回匹配某个单独值的所有行,本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而
它可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体
5.range:只检索给定范围的行,使用一个索引来选择行,key列显示使用了哪个索引
一般就是在你的where语句中出现了between,<,>,in等的查询
这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,结束于另外一个点,不用扫描全部索引
6.index:Full Index Scan,index和all区别为index类型只遍历索引树,这通常比all快,因为索引文件通常比数据文件小
也就是说孙然all和index都是读全表,但是index是从索引中读取的,而all是从硬盘中读取的
7.all:full table sacn,将遍历全表以找到匹配的行
备注:一般来说要保障查询至少达到range级别,最好能达到ref
4.possible_keys:显示可能应用在这张表中的索引,一个或者多个
查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用
5.key:实际使用的索引,如果为null,则没有使用索引
查询中若使用了覆盖索引,则该索引仅出现在key列表中
6.key_len:表示索引中使用的字节数,可以通过该列计算查询中使用的索引长度,在不损失精确性的情况下,长度越短越好
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义获得的,不是通过表内检索出的
7.ref:显示索引的哪一列被使用了,如果可能的话,是一个常数,哪些列或者常量被用于查找索引列上的值
8.rows:根据表统计信息及索引选用情况,大致估算出找到所需记录索要读取的行数(理论上越小越好)
9.extra:包含不适合在其他列展示但是十分重要的额外信息
分类可以分为:
(重要)1.Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取
Mysql中无法利用索引完成的排序操作称之为"文件排序"
(重要)2.Using temporary:使用临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于order by和分组查询group by
(重要)3.Using index:表示相应的select操作中使用了覆盖索引(Covering index),避免访问了表的数据行,效率不错!
如果同时出现了using where,表名索引别用来执行索引键值的查找
如果没有同时出现using where,表名索引用来读取数据而非执行查找动作
覆盖索引:
就是select的数据列只用从索引中就能获取到,不必读取数据行,mysql可以利用索引返回select列表中的字段
而不必根据索引再次读取数据文件,换句话说查询类要被所建的索引覆盖
如创建一个复合索引:
CREATE INDEX 索引名称 ON 表名 (字段1,字段1)
select 字段1,字段2 from 表名;
此时按照复合索引的字段和顺序进行查找,就不会再次读取数据文件,而是利用索引获取返回select列表中的字段
注意:
1.如果要使用覆盖索引,一定要注意select列表中只能取出需要的列(并且列要在复合索引内) ,不能select *
2.因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降!
4.Using where:表明使用了where条件
5.using join buffer:使用了连接缓存
6.impossible where:where字句的值总是fasle,不能来获取任何元组
7.select tables optimized away:在没有group by子句的情况下,基于索引优化MIN/MX操作或者对于MyISAM
存储引擎优化count(*)操作,不必等到执行阶段再去计算
查询执行计划生成的阶段即完成优化
8.distinct:优化distinct操作,找到第一个匹配元组后即停止赵同样值的操作
索引优化
创建一张person表,只给主键创建了索引
查询序号>2养狗的最小人的性命和年龄
explain select name,age from person t where t.pet='dog' and t.order > 2 order by t.birth desc limit 1;
联合索引(复合索引)创建面试:
1.https://www.cnblogs.com/rjzheng/p/12557314.html
2.https://www.cnblogs.com/rjzheng/category/1281020.html
双表索引
1.左连接
select * from 左表 left join 右表 on 左表.关联字段=右表.关联字段;
实质上是查询出右表符合条件的记录(一条具体记录),循环左表进行遍历,索引对遍历操作没有什么实质性帮助,主要帮助是排序,
结论:所以给右表加索引
2.右关联
select * from 左表 right join 右表 on 左表.关联字段=右表.关联字段;
左表驱动右表,即查询出左表的记录去遍历右表
结论:给左表字段加索引
join语句的优化:
1.尽可能减少jon语句中的循环总次数,"永远使用小结果集驱动大的结果集"
2.优先优化嵌套的内层循环
3.保证join语句汇总被驱动表上join条件字段已经被索引
4.当无法保证被驱动表的join条件字段被索引且内存资源充足的前提下,不要吝啬JoinBuffer的设置
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通