【Mysql 学习笔记】 高级优化 --- 索引优化分析 (非常详细,结合多个案例加深理解)

标题


----------------------- 建表语句 ----------------------------


一、性能下降SQL慢的原因 (执行时间长 等待时间长)

  • 查询语句写的差。
  • 索引失效:索引建了,但是没有用上。
  • 关联 查询太多join(设计缺陷或者不得已的需求)。
  • 服务器调优以及各个参数的设置(缓冲、线程数等)。

二、常见通用的join查询

(1) SQL执行顺序

手写顺序

在这里插入图片描述

机读顺序

在这里插入图片描述


总结

在这里插入图片描述


(2) Join图

在这里插入图片描述


三、索引简介

(1) 什么是索引

MySQL官方对索引的定义为:索引(Index)是帮助MySQL高校获取数据的数据结构。

可以得到索引的本质:索引是 数据结构

你可以简单理解为"排好序的快速查找数据结构"。

在这里插入图片描述

数据本身之外,数据库还维护着一个满足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就可以在这些数据结构的基础上实现高级查找算法,这种数据结构就是索引

扫描二维码关注公众号,回复: 12820816 查看本文章

一般来说索引本身也很大不可能全部存储在内存中,因此索引往往以文件形式存储在硬盘上

我们平时所说的索引,如果没有特别指明,都是指B树(多路搜索树,并不一定是二叉树)结构组织的索引。其中聚集索引,次要索引,覆盖索引,复合索引,前缀索引,唯一索引默认都是使用B+树索引统称索引。当然,除了B+树这种类型的索引之外,还有哈希索引(hash index)等。


(2) 索引的优势

  • 类似大学图书馆建书目索引,提高数据检索效率,降低数据库的IO成本
  • 通过索引列对数据进行排序,降低数据排序成本,降低了CPU的消耗

(3) 索引的劣势

  • 实际上索引也是一张表,该表保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占用空间的
  • 虽然索引大大提高了查询速度,同时却会降低更新表的速度,如果对表INSERT,UPDATE和DELETE。
    因为更新表时,MySQL不仅要存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息
  • 索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立优秀的索引,或优化查询语句

(4) mysql 索引分类

建议一张表索引不要超过5个 优先考虑复合索引

单值索引

即一个索引 只包含单个列一个表可以有多个单列索引


唯一索引

索引列的值必须唯一,但 允许有空值


复合索引

一个索引包含多个列


基本语法
  • 创建
方式一:
CREATE [UNIQUE] INDEX  indexName ON mytable(columnname(length));

方式二:
ALTER TABLE mytable ADD [UNIQUE]  INDEX [indexName](columnname(length));

如果是CHAR,VARCHAR类型,length可以小于字段实际长度;
如果是BLOB和TEXT类型,必须指定length。


  • 删除
DROP INDEX [indexName] ON mytable;

  • 查看
SHOW INDEX FROM table_name\G

  • 使用ALTER命令

在这里插入图片描述


(5) mysql 索引结构

  • BTree索引

Btree索引 (或Balanced Tree),是一种 很普遍的数据库索引结构oracle默认的索引类型。其 特点定位高效、利用率高、自我平衡,特别适用于高基数字段,定位单条或小范围数据非常高效。理论上,使用Btree在 亿条数据与100条数据中定位记录的花销相同

(就和二叉搜索树的原理相似,只不过这个不一定是二叉)
在这里插入图片描述


( 主要理解BTree索引,下面这三种了解即可 )

  • Hash索引
  • full-text全文索引
  • R-Tree索引

(6) 哪些情况需要创建索引

  • 主键 自动建立 主键索引(唯一 + 非空)。
  • 频繁作为查询条件的字段 应该创建索引。
  • 查询中 与其他表关联的字段,外键关系 建立索引。
  • 查询中 排序的字段,排序字段若通过索引去访问将大大提高排序速度。
  • 查询中 统计 或者 分组 字段(group by也和索引有关)。

(7) 哪些情况不要创建索引

  • 记录太少 的表。
  • 经常增删改 的表。
  • 频繁更新的字段 不适合创建索引。
  • Where条件里用不到的字段 不创建索引。
  • 数据重复且分布平均的表字段,因此应该只为经常查询和经常排序的数据列建立索引。注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。
    在这里插入图片描述

四、性能分析 (★)

(1) MySQL Query Optimizer

在这里插入图片描述


(2) MySQL常见瓶颈

  • CPU在饱和 的时候一般发生在数据装入在内存或从磁盘上读取数据时候
  • 磁盘I/O瓶颈 :发生在装入数据远大于内存容量时
  • 服务器硬件的性能瓶颈:top,free,iostat和vmstat来查看系统的性能状态

(3) Explain 执行计划

介绍

使用 EXPLAIN关键字 可以 模拟优化器执行SQL语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是结构的性能瓶颈


可获取信息
  • 表的读取顺序
  • 数据读取操作的操作类型
  • 哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询

语法
Explain+SQL语句

在这里插入图片描述


各个字段解释
① id ★

select查询的序列号,包含一组数字,表示 查询中执行select子句或操作表的顺序

可分为三种情况:

  1. id相同,执行顺序由上至下
    (案例中执行顺序为:t1 – t3 – t2
    在这里插入图片描述

  1. id不同,如果是子查询,id的序号会递增id值越大优先级越高,越先被执行
    (案例中执行顺序为:t3 – t1 – t2
    在这里插入图片描述

  1. id相同不同,同时存在
    (案例中执行顺序为:t3 – derived2 – t2derived2 代表从id=2衍生出来的,也就是s1 (虚表)
    在这里插入图片描述

② select_type

查询的类型,主要用于区别 普通查询联合查询子查询等的复杂查询

  • SIMPLE:简单的select查询,查询中不包含子查询或者UNION
  • PRIMARY:查询中若 包含任何复杂的子部分最外层查询被标记为PRIMARY
  • SUBQUERY:在 SELECT或者WHERE 列表中包含了子查询
  • DERIVED:在 FROM 列表中包含的子查询被标记为DERIVED(衍生) MySQL会递归执行这些子查询,把 结果放在临时表 里。
  • UNION:若第二个SELECT出现在UNION之后,则被标记为UNION;
    UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
  • UNION RESULT:从UNION表获取结果的SELECT

③ table

显示这一行的数据是关于哪张表的


④ type ★

显示查询使用了何种类型
最好到最差 依次是 ( 常见的类型 ):
system > const > eq_ref > ref > range > index > ALL

一般来说,得保证查询只是达到 range级别最好达到 ref

在这里插入图片描述

  • system

表只有一行记录(等于系统表),这是const类型的特例,平时不会出现,这个也可以 忽略不计


  • const

表示 通过索引一次就找到了,const用于比较 primary key或者unique 索引。因为只匹配一行数据,所以很快 将主键至于where列表中,MySQL就能将该查询转换为一个常量

在这里插入图片描述


  • eq_ref

唯一性索引,对于每个索引键表中只有一条记录与之匹配,常见于主键或唯一索引扫描

在这里插入图片描述


  • ref

非唯一索引扫描,返回匹配某个单独值的所有行。
本质上也是一种索引访问,它返回所有匹配某个单独值的行,然而,
可能会找到多个符合条件的行,所以他应该属于查找和扫描的混合体

在这里插入图片描述


  • range

检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引
一般就是在你的 where语句中 出现了between、<、>、in等的查询
这种范围扫描索引扫描比全表扫描要好,因为他只需要开始索引的某一点,而结束语另一点,不用扫描全部索引

在这里插入图片描述


  • index

Full Index Scan,index与ALL区别index类型只遍历索引树。这通常比ALL快,因为索引文件通常比数据文件小。
(也就是说虽然all和index都是读全表,但index是从索引中读取的,而all是从硬盘中读的)


  • all

FullTable Scan,将遍历全表以找到匹配的行

在这里插入图片描述


⑤ possible_keys

显示 可能应用这张表中的索引,一个或多个。
查询涉及的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用


⑥ key ★

实际使用的索引。如果 为 null 则没有使用索引
查询中若使用了覆盖索引,则索引和查询的select字段重叠


⑦ key_len

表示 索引中使用的字节数,可通过该列计算查询中使用的索引的长度。在不损失精确性的情况下,长度越短越好

key_len显示的值 为索引最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的


⑧ ref

显示索引哪一列被使用了,如果可能的话,是一个常数。那些列或常量被用于查找索引列上的值


⑨ rows

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数


⑩ Extra ★

包含 不适合在其他列中显示十分重要的额外信息
(重点关注前三个打⭐的,其他的了解即可)

  • Using filesort ★ (危)

说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。
MySQL中无法利用索引完成排序操作成为“文件排序”

在这里插入图片描述
在这里插入图片描述


  • Using temporary ★ (极危)

使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于 排序 order by分组查询 group by

在这里插入图片描述


  • USING index ★ (喜)

这里是引用表示相应的select操作中使用了覆盖索引(Coveing Index),避免访问了表的数据行,效率不错!
如果同时出现using where,表明 索引被用来执行索引键值的查找
如果没有同时出现using where,表明 索引用来读取数据非执行查找动作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


  • Using where

表明使用了where过滤


  • using join buffer

使用了连接缓存


  • impossible where

where子句的值总是false,不能用来获取任何元组


  • select tables optimized away

没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者
对于MyISAM存储引擎优化COUNT(*)操作不必等到执行阶段再进行计算,
查询执行计划生成的阶段即完成优化。


  • distinct

优化distinct,在找到第一匹配的元组后即停止找同样值的工作


热身Case

在这里插入图片描述
在这里插入图片描述


五、索引优化 (★)

(1) 索引分析

单表索引分析

此处得出结论:范围之后全失效

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


两表索引分析

此处得出结论:左连接 建在 右边的表右连接 建在 左边的表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


三表索引分析

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


JOIN语句的优化

尽可能减少JOIN语句中的NestedLoop(嵌套循环)的总次数:永远都是小的结果集驱动大的结果集。

优先优化NestedLoop的内层循环。

保证JOIN语句中被驱动表上JOIN条件字段已经被索引。

当无法保证被驱动表的JOIN条件字段被索引且内存资源充足的前提下,不要太吝惜Join Buffer 的设置。


(2) 索引失效 (应该避免)

索引失效的的一些案例
① 全值匹配我最爱

全值匹配我最爱

在这里插入图片描述
在这里插入图片描述


② 最佳左前缀法则 ( 如果索引了多例,要遵守最左前缀法则。指的是查询从索引的最左前列开始并且不跳过索引中的列。)

最左前缀要遵守,带头大哥不能s,中间兄弟不能断

在这里插入图片描述


③ 不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描

索引列上少计算

在这里插入图片描述


④ 存储引擎不能使用索引中范围条件右边的列

范围之后全失效

在这里插入图片描述


⑤ 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select*

覆盖索引不写星

在这里插入图片描述


⑥ mysql在使用不等于( != 或者 <>)的时候无法使用索引可能会导致全表扫描

在这里插入图片描述


⑦ is null,is not null 也无法使用索引

在这里插入图片描述


⑧ like以通配符开头(’%abc…’)mysql索引失效会变成全表扫描操作

LIKE百分写最右

(图片里,type是range,写错了。。。)

在这里插入图片描述
在这里插入图片描述

问题:解决like’%字符串%'索引不被使用的方法??

  • 可以使用主键索引
  • 使用覆盖索引,查询字段必须是建立覆盖索引字段
  • 当覆盖索引指向的字段是varchar(380)及380以上的字段时,覆盖索引会失效!
    在这里插入图片描述

⑨ 字符串不加单引号索引失效

VAR引号不可丢

在这里插入图片描述


⑩ 少用or,用它连接时会索引失效

6、7、10:不等空值还有or,索引失效要少用

在这里插入图片描述


小总结

在这里插入图片描述


索引题目练习
Where语句 索引是否被使用
where a = 3 Y,使用到a
where a = 3 and b = 5 Y,使用到a,b
where a = 3 and b = 5 and c = 4 Y,使用到a,b,c
where b = 3 或者 where b = 3 and c = 4 或者 where c = 4 N,没有用到a字段
where a = 3 and c = 5 使用到a,但是没有用到c,因为b断了
where a = 3 and b > 4 and c = 5 使用到a,b,但是没有用到c,因为c在范围之后
where a = 3 and b like ‘kk%’ and c = 4 Y,a,b,c都用到
where a = 3 and b like ‘%kk’ and c = 4 只用到a
where a = 3 and b like ‘%kk%’ and c = 4 只用到a
where a = 3 and b like ‘k%kk%’ and c = 4 Y,a,b,c都用到

面试题

复合索引的使用就类似于一个 搭梯子 的过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


(3) 一般性建议

  • 对于 单键索引,尽量 选择针对当前query过滤性更好的索引
  • 在选择 组合索引 的时候,当前 Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。
  • 在选择 组合索引 的时候,尽量选择可以能包含当前query中的where子句中更多字段的索引
  • 尽可能通过 分析统计信息调整query的写法达到选择合适索引的目的

个人疑惑总结 — 全值匹配 和 覆盖索引

个人总结,全值匹配覆盖索引 傻傻分不清,经过不断分析,貌似有了一点点理解,记录一下


覆盖索引:就是 select后 的东西都得是 索引中的字段 或者 主键 (因为主键自带主键索引),一旦 select 了 其他字段,索引就会失效,type 变为 all


全值匹配:可以 select 所有字段,但是 必须满足 “带头大哥不能s,中间兄弟不能断”,否则索引就会失效,type 变为 all

在这里插入图片描述


猜你喜欢

转载自blog.csdn.net/weixin_45260385/article/details/114745799