MySQL之SQL性能(1)——索引、explain

目录

1.索引

(1)索引介绍

1)什么是索引?

2)索引的优势

3)索引的劣势

(2)mysql索引分类和语法

1)索引分类

2)语法

(3)mysql索引结构

(4)哪些情况需要建索引?

(5)哪些情况不需要建索引?

2.性能分析——explain

(1)mysql优化器

(2)MySQL的常见瓶颈

(3)查询执行计划——explain

1)explain简介

2)执行计划的信息各字段解释

(1)id

(2)select_type

(3)table

(4)type

(5)possible_keys和key

(6)key_len

(7)ref

(8)rows

(9)Extra

(10)案例分析示例


1.索引

(1)索引介绍

1)什么是索引?

  • 索引是排好序的快速查找数据结构
  • 索引的目的:提高查找效率
  • 现实中的示例:
  • 1.字典,如果在字典中我们要查找mysql,我们会先找m,并且字母按照顺序排好的,我们可以快速查找到该字母,索引同理,两大功能:1.排好序  2.查找快
  • 2.图书馆,.图书馆中的每一本书都建好了索引,图书馆前台维护着书籍的索引查询表,里面存放着书籍存放地址,这样就可以根据图书的索引查询到该图书所在的位置,否则,如果没有这个索引,只能遍历所有图书去找
  • 所以索引会影响SQL语句中的两大部分:
  1. where后面的查找筛选
  2. order by后面的排序
  • 在数据之外,数据库还维护着满足特定查找算法的数据结构,这种数据结构以某种方式引用指向数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引

为了开发的程序查的快,DBA要对每天的数据备份、恢复、建索引,在做开发时,我们一般在delete的时候不会真正去调用真正的delete方法去物理删除数据库中的数据,而是逻辑删除,通过update方法把标志位从激活状态变为非激活状态,实际上数据物理上还是存在,这样做的原因:

  1. 为了数据分析(别的部门可能会用)
  2. 为了索引

         解释:在频繁地进行了数据地增加、修改、删除之后,慢慢的索引的查找会失效,因为此时索引可能指不准,也可能是空的,查找就会挂,所以一些DBA会进行重建索引的工作

为什么查询快,增删改慢呢?

答:因为在增删改的时候除了改它本身的记录,还要改该图书的索引,所以频繁删改的字段不适合建索引

  • 一般来说,索引本身也很大,不可能全部存储在内存中,因此索引往往以索引文件的形式存储在磁盘上
  • 此处学习所使用到的都是B树索引,其中聚集索引、次要索引、覆盖索引、复合索引、唯一索引默认都是使用B+树索引

2)索引的优势

  • 提交了检索效率,降低了数据库的IO成本
  • 通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗

3)索引的劣势

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

(2)mysql索引分类和语法

1)索引分类

  • 单值索引:一个索引只包含单个列,一个表可以有多个单列索引
  • 复合索引:
  • 唯一索引:索引列的值必须唯一,但允许有空值
  • 建复合索引优于单值索引,因为生活中的习惯很多都会依照多值来查,当然针对频繁使用的一些字段,可以建立单值索引
  • 一般而言,一张表建的索引不要超过5个
  • 同一时间,只能加载一个索引值用

2)语法

  • 创建
CREATE [UNIQUE] INDEX indexName ON 表名(列名(长度))
或
ALTER 表名 ADD [UNIQUE] INDEX [indexName] ON (列名(长度))

  • 删除
DROP INDEX [indexName] ON 表名
  • 查看
SHOW INDEX FROM 表名

(3)mysql索引结构

  • BTree索引

MySQL之SQL性能(1)——索引、explain_第1张图片

MySQL之SQL性能(1)——索引、explain_第2张图片

MySQL之SQL性能(1)——索引、explain_第3张图片

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

(4)哪些情况需要建索引?

  • 1.主键自动建立唯一索引
  • 2.频繁作为查询条件的字段应该创建索引,比如说银行系统的银行账号,电信系统的手机号
  • 3.查询中与其他表关联的字段,外键关系建立索引
  • 4.单值索引还是复合索引?(在高并发情况下倾向创建复合索引)
  • 5.查询中排序字段,排序的字段若通过索引去访问将大大提高排序速度
  • 6.查询中统计或者分组的字段(因为分组的前提是必排序)

(5)哪些情况不需要建索引?

  • 1.表的记录太少(经验里MySQL300万的数据量,性能开始下降,就需要去优化)
  • 2.经常增删改的表不适合创建索引
  • 3.数据重复且分布平均的表字段,因为某些数据列包含许多重复的内容,为它建立索引就没有实际太大的效果,比如性别这个字段,不是男,就是女,重复很多,为该字段建立索引没有实际的效果
  • MySQL之SQL性能(1)——索引、explain_第4张图片
  • 4.where条件里用不到的字段不用创建索引

2.性能分析——explain

(1)mysql优化器

MySQL之SQL性能(1)——索引、explain_第5张图片

(2)MySQL的常见瓶颈

  • 1.CPU:瓶颈发生在CPU在饱和的时候,一般发生在数据装入内存的时候或从磁盘上读取数据的时候
  • 2.IO:磁盘IO瓶颈发生在数据装入远大于内存容量的时候
  • 3.服务器硬件的性能瓶颈(机器本身的硬件或以及各种配置):top,free,iostat和vmstat来查看系统性能状态

(3)查询执行计划——explain

1)explain简介

  • 1.是什么?
  • explain用于查看执行计划,
  • 使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的,分析你的查询语句或是表的结构的性能瓶颈
  • 2.能干嘛?(可以结合后面对explain执行后各字段解释来理解,每一条请看后面对括号中该字段的的解释再来理解)
  •     表的读取顺序(id)
  •     数据读取操作的操作类型(select_type)
  •     哪些索引可以使用(possible_keys)
  •     哪些索引被实际使用(key)
  •     表之间的引用(ref)
  •     每张表有多少行被优化器查询(rows)
  • 3.怎么用
  •     explain + sql语句
  • 执行计划中包含的信息如下:

2)执行计划的信息各字段解释

  • (1)id

  • (a)id相同,执行顺序由上至下
  • MySQL之SQL性能(1)——索引、explain_第6张图片
  • t1,t2,t3表的id是相同的,所以MySQL对该三个表的执行顺序是从上至下,即t1,t3,t2
  • (b)id不同,如果是子查询,id的序号会递增,id值越大,优先级越高,越先被执行
  • MySQL之SQL性能(1)——索引、explain_第7张图片
  • t1,t2,t3表的id分别是1,2,3,所以MySQL对该三个表的执行顺序是从上至下,即t3,t1,t2
  • (c)id相同和不同,同时存在,id越大越先执行,然后,id相同时,又按顺序执行
  • MySQL之SQL性能(1)——索引、explain_第8张图片
  • 解释:table中derived即为衍生的表,后面所跟数字2是它所衍生自的表的id
  • 所以上述表的执行顺序为t3,,t2
  • (2)select_type

  • 查询类型,主要用于区别普通查询、联合查询、子查询等的复杂查询
  • 有以下6种:
  • MySQL之SQL性能(1)——索引、explain_第9张图片
  •     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)table

  • 显示这一行是哪张表的
  • (4)type

  • 即MySQL决定的如何去查询表中的行的方式
  • 有以下类型:
  • type显示查询使用了何种类型,从最好到最差依次是:
  • system>const>eq_ref>ref>range>index>ALL
  • 一般来说,得保证查询至少达到range级别,最好能达到ref

各种类型解释

  • 1.system:表中只有一条记录(只有一条数据的系统表衍生表只能有一条数据的主查询),这是const类型的特例,平时不会出现,这个也可以忽略不计
  • 2.const:表示通过索引一次就找到了,const必须用于比较primary key 或unique索引,因为与之匹配一行数据,索引很快,如将主键置于where列表中,MySQL就能将该查询转换为一个常量
  • MySQL之SQL性能(1)——索引、explain_第10张图片
  • 上图中id为主键,子查询select * from t1 where id=1只会匹配到一条记录,该子查询使用主键索引从多条记录中只匹配最终结果为一条记录,所以为const,而外层查询从一条记录的临时表dervied2中匹配一条记录,所以更快,为system
  • 以上在企业里基本不可能实现
  • 3.eq_ref:根据索引查找,最多只返回一个符合条件的记录,但是需要额外与某个参考值做比较
  • const和eq_ref的区别:const是直接按主键或唯一键读取,eq_ref用于联表查询的情况,按联表的主键或唯一键联合查询。
  • MySQL之SQL性能(1)——索引、explain_第11张图片
  • 该查询先加载t2进行全表扫描,但是当扫描t1时,t1中只有一条记录与之匹配
  • 比如找出一个公司的CEO,只有一个与之匹配
  • 4.ref:根据索引返回匹配某个单值的所有行,它可能会找到多个符合条件的行,所以它应属于查找和扫描的混合体
  • 简单来说:用到的索引查出了多条记录
  • MySQL之SQL性能(1)——索引、explain_第12张图片
  • 从t1中找出col1='ac'的记录有多行与之匹配
  • 比如找出一个公司的所有程序员
  • 5.range:根据索引实现范围扫描,只需要遍历指定索引范围内的表中的所有行
  • 使用一个索引来选择行,key列显示使用了哪个索引,一般就是在where语句中出现between、>、<、in等的查询,这种范围索引扫描比全表扫描要好,因为它只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引
  • MySQL之SQL性能(1)——索引、explain_第13张图片
  • 划定了范围,做了一些过滤
  • 6.index:根据索引的次序进行全表扫描,如果在Extra列中出现了“using index”,表示使用了覆盖索引
  • 使用覆盖索引比使用索引扫描表好很多,因为覆盖索引只扫描索引,而不扫描表本身
  • index与ALL的区别是index只遍历索引树,这通常比ALL快,因为索引文件通常比数据文件小(也就是说index和ALL都是读全表,index是从索引中读取,ALL是从硬盘中读取)
  • id是主键索引,使用了索引,所以为index
  • 7.ALL:遍历全表找到与之匹配的行
  • 百万级别以上出现了ALL就要考虑进行优化
  • 8.NULL:MySQL能在优化阶段能分解查询语句,在执行阶段不用访问表或者索引
  • (5)possible_keys和key

possible_keys

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

key

  • 实际使用的索引,如果为NULL,则没有使用索引,或索引失效
  • 查询中若使用了覆盖索引,则该索引只出现在key列表中
  • MySQL之SQL性能(1)——索引、explain_第14张图片
  • 如上,覆盖索引即是select后查询的字段与创建复合索引的字段个数的顺序一致
  • MySQL之SQL性能(1)——索引、explain_第15张图片
  • (6)key_len

  • 表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度,在不损失精确性的情况下,长度越短越好
  • key_len显示的是索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,而不是通过表内检索出的
  • MySQL之SQL性能(1)——索引、explain_第16张图片
  • (7)ref

  • 在利用key中所表示的索引进行查询时,所用的列或某常量值,即可查看表之间的引用,当key中为NULL时,ref也为NULL
  • MySQL之SQL性能(1)——索引、explain_第17张图片
  • 上述ref栏中三行分别表示:
  •      第一行const:用索引idx_t1在t1表中查询时,根据常量来进行查找
  •      第二行test.t1.ID:用主键索引在t3表中查询时,根据test库中的t1表的ID字段进行查找
  •      第三行test.t1.ID:用主键索引在t2表中查询时,根据test库中的t1表的ID字段进行查找
  • (8)rows

  • 根据表统计信息及索引选用情况,大致估算出找到所需记录需要读取的行数,越少越好
  • MySQL之SQL性能(1)——索引、explain_第18张图片
  • (9)Extra

  • 包含不适合在其他列中显示但十分重要的额外信息
  • 1.Using filesort:出现之后性能低下,需要优化
  • 说明mysql会对数据使用外部的索引排序,而不是按照表内的索引顺序进行读取,mysql中无法利用索引完成的排序操作称为“文件排序”
  • MySQL之SQL性能(1)——索引、explain_第19张图片
  • 2.Using tempoary:出现之后性能低下,需要优化
  • 使用了临时表保存中间结果,mysql在对查询结果排序时使用了临时表,常见于排序order by和分组查询group by
  • MySQL之SQL性能(1)——索引、explain_第20张图片
  • group by后的字段要么别建索引,要么其后尽量按照建索引的顺序来,否则特别容易产生文件排序
  • 3.Using Index:出现之后性能高
  • 表示相应的select操作中使用了覆盖索引,避免访问了表的数据行,效率不错,
  • 如果同时出现Using where,表明索引被用来执行索引键值的查找
  • 如果没有同时出现Using where,表明索引用来读取数据而非执行查找动作
  • MySQL之SQL性能(1)——索引、explain_第21张图片
  • 4.Using where:
  • 表明使用了where过滤
  • 5.Using join buffer:
  • 使用了连接缓存
  • 6.impossible where:
  • where子句的值是false,不能用来获取任何元组
  • MySQL之SQL性能(1)——索引、explain_第22张图片
  • 7.select tables optimized away:
  • 在没有group by子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算
  • 查询执行计划生成的阶段即完成优化
  • 8.distinct:
  • 优化distinct操作,再找到第一个匹配的元组即停止找同样的元组的动作
  • (10)案例分析示例

MySQL之SQL性能(1)——索引、explain_第23张图片

MySQL之SQL性能(1)——索引、explain_第24张图片

你可能感兴趣的:(MySQL)