美文网首页数据库
2 mysql索引优化分析

2 mysql索引优化分析

作者: Java及SpringBoot | 来源:发表于2018-06-07 09:07 被阅读48次

2.1 性能下降SQL慢 执行时间长 等待时间长

2.1.1 查询语句写的烂

2.1.2 索引失效

单值

复合

2.1.3 关联查询太多join(设计缺陷或不得已的需求)

2.1.4 服务器调优及各个参数设置(缓冲\线程数等)

2.2 常见通用的join查询

2.2.1 SQL执行顺序

手写

clip_image040.jpg

机读

clip_image042.jpg

总结

clip_image044.jpg

2.2.2 Join图

clip_image046.jpg

2.2.3 建表SQL

2.2.4 7种Join

2.3 索引简介

2.3.1 是什么

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

clip_image048.jpg

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

详解(重要)

clip_image050.jpg

结论

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

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

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

2.3.2 优势

类似大学图书馆建书目索引,提高数据检索效率,降低数据库的IO成本

通过索引列对数据进行排序,降低数据排序成本,降低了CPU的消耗

2.3.3 劣势

实际上索引也是一张表,该表保存了主键和索引字段,并指向实体表的记录,所以索引列也是要占用空间的

虽然索引大大提高了查询速度,同时却会降低更新表的速度,如果对表INSERT,UPDATE和DELETE。 因为更新表时,MySQL不仅要不存数据,还要保存一下索引文件每次更新添加了索引列的字段, 都会调整因为更新所带来的键值变化后的索引信息

索引只是提高效率的一个因素,如果你的MySQL有大数据量的表,就需要花时间研究建立优秀的索引,或优化查询语句

2.3.4 mysql索引分类

单值索引

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

建议一张表索引不要超过5个

优先考虑复合索引

唯一索引

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

复合索引

即一个索引包含多个列

基本语法

创建

CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));

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

ALTER mytable ADD [UNIQUE] INDEX [indexName] ON(columnname(length));

删除

DROP INDEX [indexName] ON mytable;

查看

SHOW INDEX FROM table_name\G

使用ALTER命令

clip_image052.jpg

2.3.5 mysql索引结构

BTree索引

clip_image054.jpg clip_image056.jpg

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

数据结构利用率高、定位高效

Btree索引的数据结构如下:

clip_image058.jpg

结构看起来Btree索引与Binary Tree相似,但在细节上有所不同,上图中用不同颜色的标示出了Btree索引的几个主要特点:

树形结构:由根节(root)、分支(branches)、叶(leaves)三级节点组成,其中分支节点可以有多层。

多分支结构:与binary tree不相同的是,btree索引中单root/branch可以有多个子节点(超过2个)。

双向链表:整个叶子节点部分是一个双向链表(后面会描述这个设计的作用)

单个数据块中包括多条索引记录

这里先把几个特点罗列出来,后面会说到各自的作用。

结构上Btree与Binary Tree的区别,在于binary中每节点代表一个数值,而balanced中root和Btree节点中记录了多条”值范围”条目(如:[60-70][70-80]),这些”值范围”条目分别指向在其范围内的叶子节点。既root与branch可以有多个分支,而不一定是两个,对数据块的利用率更高。

在Leaf节点中,同样也是存放了多条索引记录,这些记录就是具体的索引列值,和与其对应的rowid。另外,在叶节点层上,所有的节点在组成了一个双向链表。

了解基本结构后,下图展示定位数值82的过程:

clip_image060.jpg

演算如下:

读取root节点,判断82大于在0-120之间,走左边分支。

读取左边branch节点,判断82大于80且小于等于120,走右边分支。

读取右边leaf节点,在该节点中找到数据82及对应的rowid

使用rowid去物理表中读取记录数据块(如果是count或者只select rowid,则最后一次读取不需要)

在整个索引定位过程中,数据块的读取只有3次。既三次I/O后定位到rowid。

而由于Btree索引对结构的利用率很高,定位高效。当1千万条数据时,Btree索引也是三层结构(依稀记得亿级数据才是3层与4层的分水岭)。定位记录仍只需要三次I/O,这便是开头所说的,100条数据和1千万条数据的定位,在btree索引中的花销是一样的。

平衡扩张

除了利用率高、定位高效外,Btree的另一个特点是能够永远保持平衡,这与它的扩张方式有关。(unbalanced和hotspot是两类问题,之前我一直混在一起),先描述下Btree索引的扩张方式:

新建一个索引,索引上只会有一个leaf节点,取名为Node A,不断的向这个leaf节点中插入数据后,直到这个节点满,这个过程如下图(绿色表示新建/空闲状态,红色表示节点没有空余空间):

clip_image062.jpg

当Node A满之后,我们再向表中插入一条记录,此时索引就需要做拆分处理:会新分配两个数据块NodeB & C,如果新插入的值,大于当前最大值,则将Node A中的值全部插入Node B中,将新插入的值放到Node C中;否则按照5-5比例,将已有数据分别插入到NodeB与C中。

无论采用哪种分割方式,之前的leaf节点A,将变成一个root节点,保存两个范围条目,指向B与C,结构如下图(按第一种拆分形式):

clip_image064.jpg

当Node C满之后,此时 Node A仍有空余空间存放条目,所以不需要再拆分,而只是新分配一个数据块Node D,将在Node A中创建指定到Node D的条目:

clip_image066.jpg

如果当根节点Node A也满了,则需要进一步拆分:新建Node E&F&G,将Node A中范围条目拆分到E&F两个节点中,并建立E&F到BCD节点的关联,向Node G插入索引值。此时E&F为branch节点,G为leaf节点,A为Root节点:

clip_image068.jpg

在整个扩张过程中,Btree自身总能保持平衡,Leaf节点的深度能一直保持一致。

实际应用中的一些问题

前面说完了Btree索引的结构与扩张逻辑,接下来讲一些Btree索引在应用中的一些问题:

单一方向扩展引起的索引竞争(Index Contention)

若索引列使用sequence或者timestamp这类只增不减的数据类型。这种情况下Btree索引的增长方向总是不变的,不断的向右边扩展,因为新插入的值永远是最大的。

当一个最大值插入到leaf block中后,leaf block要向上传播,通知上层节点更新所对应的“值范围”条目中的最大值,因此所有靠右边的block(从leaf 到branch甚至root)都需要做更新操作,并且可能因为块写满后执行块拆分。

如果并发插入多个最大值,则最右边索引数据块的的更新与拆分都会存在争抢,影响效率。在AWR报告中可以通过检测enq: TX – index contention事件的时间来评估争抢的影响。解决此类问题可以使用Reverse Index解决,不过会带来新的问题。

Index Browning 索引枯萎(不知道该怎么翻译这个名词,就是指leaves节点”死”了,树枯萎了)

其实oracle针对这个问题有优化机制,但优化的不彻底,所以还是要拿出来的说。

我们知道当表中的数据删除后,索引上对应的索引值是不会删除的,特别是在一性次删除大批量数据后,会造成大量的dead leaf挂到索引树上。考虑以下示例,如果表100以上的数据会部被删除了,但这些记录仍在索引中存在,此时若对该列取max():

clip_image070.jpg

通过与之前相同演算,找到了索引树上最大的数据块,按照记录最大的值应该在这里,但发现这数据块里的数据已经被清空了,与是利用Btree索引的另一个特点:leaves节点是一个双向列表,若数据没有找到就去临近的一个数据块中看看,在这个数据块中发现了最大值99。

在计算最大值的过程中,这次的定位多加载了一个数据块,再极端的情况下,大批量的数据被删除,就会造成大量访问这些dead leaves。

针对这个问题的一般解决办法是重建索引,但记住! 重建索引并不是最优方案,详细原因可以看看这。使用coalesce语句来整理这些dead leaves到freelist中,就可以避免这些问题。理论上oracle中这步操作是可以自动完成的,但在实际中一次性大量删除数据后,oracle在短时间内是反应不过来的。

Hash索引

了解

full-text全文索引

了解

R-Tree索引

了解

2.3.6 哪些情况需要创建索引

1.主键自动建立唯一索引

2.频繁作为查询的条件的字段应该创建索引

3.查询中与其他表关联的字段,外键关系建立索引

4.频繁更新的字段不适合创建索引

因为每次更新不单单是更新了记录还会更新索引,加重IO负担

5.Where条件里用不到的字段不创建索引

6.单间/组合索引的选择问题,who?(在高并发下倾向创建组合索引)

7.查询中排序的字段,排序字段若通过索引去访问将大大提高排序的速度

8.查询中统计或者分组字段

2.3.7 哪些情况不要创建索引

1.表记录太少

2.经常增删改的表

3.数据重复且分布平均的表字段,因此应该只为经常查询和经常排序的数据列建立索引。 注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。

clip_image072.jpg

2.4 性能分析

2.4.1 MySQL Query Optimizer

clip_image074.jpg

2.4.2 MySQL常见瓶颈

CPU:CPU在饱和的时候一般发生在数据装入在内存或从磁盘上读取数据时候

IO:磁盘I/O瓶颈发生在装入数据远大于内存容量时

服务器硬件的性能瓶颈:top,free,iostat和vmstat来查看系统的性能状态

2.4.3 Explain

是什么(查看执行计划)

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

官网介绍

能干嘛

表的读取顺序

数据读取操作的操作类型

哪些索引可以使用

哪些索引被实际使用

表之间的引用

每张表有多少行被优化器查询

怎么玩

Explain+SQL语句

执行计划包含的信息

clip_image076.png

各个字段解释

id

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

三种情况

id相同,执行顺序由上至下

clip_image078.jpg

id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

clip_image080.jpg

id相同不同,同时存在

clip_image082.jpg

select_type

有哪些

clip_image083.png

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

1.SIMPLE

简单的select查询,查询中不包含子查询或者UNION

2.PRIMARY

查询中若包含任何复杂的子部分,最外层查询则被标记为

3.SUBQUERY

在SELECT或者WHERE列表中包含了子查询

4.DERIVED

在FROM列表中包含的子查询被标记为DERIVED(衍生) MySQL会递归执行这些子查询,把结果放在临时表里。

5.UNION

若第二个SELECT出现在UNION之后,则被标记为UNION; 若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED

6.UNION RESULT

从UNION表获取结果的SELECT

table

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

type

clip_image085.png

Subtopic

访问类型排列

clip_image087.jpg

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

system

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

const

clip_image089.jpg

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

eq_ref

clip_image091.jpg

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

ref

clip_image093.jpg

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

range

clip_image095.jpg

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

index

clip_image097.jpg

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

all

clip_image099.jpg

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

备注:

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

possible_keys

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

key

实际使用的索引。如果为null则没有使用索引

查询中若使用了覆盖索引,则索引和查询的select字段重叠

参阅: 3.USING index

key_len

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

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

clip_image101.jpg

ref

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

clip_image103.jpg

rows

clip_image105.jpg

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

越少越好

Extra

包含不适合在其他列中显示但十分重要的额外信息

1.Using filesort

clip_image107.jpg

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

2.Using temporary

clip_image109.jpg

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

3.USING index

clip_image111.jpg

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

覆盖索引(Covering Index)

clip_image113.jpg

4.Using where

表面使用了where过滤

5.using join buffer

使用了连接缓存

6.impossible where

clip_image115.jpg

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

7.select tables optimized away

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

8.distinct

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

热身Case

clip_image117.jpg clip_image119.jpg

2.5 索引优化

2.5.1 索引分析

clip_image121.jpg clip_image123.jpg

单表

建表SQL

案例

两表

建表SQL

案例

三表

建表SQL

案例

clip_image125.jpg clip_image127.jpg

2.5.2 索引失效(应该避免)

建表SQL

案例(索引失效)

1.全值匹配我最爱

clip_image129.jpg

2.最佳左前缀法则

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

clip_image131.jpg

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

clip_image133.jpg

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

clip_image135.jpg

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

clip_image137.jpg clip_image139.jpg

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

clip_image141.jpg

7.is null,is not null 也无法使用索引

clip_image143.jpg

8.like以通配符开头('$abc...')mysql索引失效会变成全表扫描操作

clip_image145.jpg

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

1、可以使用主键索引

2、使用覆盖索引,查询字段必须是建立覆盖索引字段

3、当覆盖索引指向的字段是varchar(380)及380以上的字段时,覆盖索引会失效!

9.字符串不加单引号索引失效

clip_image147.jpg

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

clip_image149.jpg

11.小总结

clip_image151.jpg

like KK%相当于=常量 %KK和%KK% 相当于范围

clip_image153.jpg

定值、范围还是排序,一般order by是给个范围

group by 基本上都需要进行排序,会有临时表产生

2.5.3 一般性建议

对于单键索引,尽量选择针对当前query过滤性更好的索引

在选择组合索引的时候,当前Query中过滤性最好的字段在索引字段顺序中,位置越靠前越好。

在选择组合索引的时候,尽量选择可以能包含当前query中的where子句中更多字段的索引

尽可能通过分析统计信息和调整query的写法来达到选择合适索引的目的

相关文章

  • MySQL相关文章索引(2)

    1.MySQL性能优化 对MySQL语句的性能分析与优化 Mysql 监控 Innodb 阻塞状况 MySQL索引...

  • mysql性能优化-慢查询分析、优化索引和配置

    mysql性能优化-慢查询分析、优化索引和配置 分类:Mysql/postgreSQL 目录 一、优化概述 二、查...

  • MySQL索引优化分析

    MySQL索引优化分析 - 云+社区 - 腾讯云 MySQL · 答疑释惑· using filesort VS ...

  • MySQL Explain命令用法

    引用自 MySQL 性能优化神器 Explain 使用分析 一、介绍 explain显示了mysql如何使用索引...

  • 1. Mysql索引数据结构详解

    一. 索引优化面试题分析 1.1 分析以下几条sql的索引使用情况 二. 索引到底是什么 索引是帮助MySQL高效...

  • mysql数据库优化

    1. Mysql优化介绍 1.1 sql优化 a. sql优化分析b. 索引优化c. 常用sql优化d. 常用优化...

  • SQL索引优化实战

    索引是帮助MySQL高效获取数据的排好序的数据结构。在学习索引优化之前建议先学习 mysql索引数据结构在分析SQ...

  • MySQL 索引及查询优化总结-2018-03-20

    MySQL 索引及查询优化总结 文章《MySQL查询分析》讲述了使用MySQL慢查询和explain命令来定位my...

  • 2 mysql索引优化分析

    2.1 性能下降SQL慢 执行时间长 等待时间长 2.1.1 查询语句写的烂 2.1.2 索引失效 单值 复合 ...

  • Innodb 索引

    explain1explain2MySQL索引原理及慢查询优化项目中常用的19条MySQL优化mysql 中 my...

网友评论

    本文标题:2 mysql索引优化分析

    本文链接:https://www.haomeiwen.com/subject/iluwsftx.html