Mysql索引

Mysql索引

一、什么是索引

什么是索引,我们想到的是查询慢了,设置索引呗!但是索引为什么起作用?设置了索引为什么还是慢我其实不是特别的清楚。
在关系数据库中,索引是一种数据结构,它将数据提前按照一定的规则进行排序和组织,能够帮助快速定位到数据记录的数据,加快数据库表中数据的查询和访问速度。像数据的目录、文件夹、标签、房号、……

能实现快速定位数据的一种存储结构,其实思想是以空间换时间

二、索引的种类

在Mysql中索引是在存储引擎层实现的,而不是咋服务层实现的,所以不同存储引擎具有不用的索引类型和实现,常见的索引分类如下:

  • 按数据结构分类:B+tree索引(默认)、Hash索引(memory引擎支持)、Full-text索引
  • 按物理存储分类:聚集索引、非聚集索引(可以认为INnoDB的存储方式是聚集索引,MyISAM的存储方式是非聚集索引)
  • 按字段特性分类:主键索引(PEIMARY KEY)、唯一索引(UNIQUE)、普通索引(INDEX)、全文索引(FULLTEXT)
  • 安字段个数分类:单列索引、联合索引(也叫复合索引、组合索引)

三、常见索引数据结构和区别

  • 二叉树、红黑树、B树、B+树
  • 区别:树的高度影响获取数据的性能(每个树节点都是一次磁盘I/O)

(一)、二叉树 (查询效率O(n))

特点:每个节点最多有两个子节,大在左,小在右,数据随机性情况下树权越明显。
在这里插入图片描述

(二)、红黑树(平衡二叉树)

红黑树

(三)、B树

Btree

(四)、B+树

B+tree

(五)、B树和B+树的区别

MySQL为什么要选择B+树作为默认索引的数据结构
在这里插入图片描述
B+tree 结构实现数据索引具有如下优点:

a.非叶子节点上可以储存更多的键值,相应的树阶数(节点的子节点树)就会更大,树也就会变得更矮更胖。这样一来我们查找数据进项磁盘I/O的次数就会大大减少,数据查询的效率也会更快。

b.所有数据记录都会有序存储到叶子节点上,就会使得查找,排序查找,分组超找以及去重查找变得异常简单。

c. 数据页之间、数据记录之间都是通过链表链接的,有了这个结构的支持就可以方便的在数据查询后进行升序或者降序操作。

问题:如有一个 表没有主键索引还会创建B+树吗?
答案: 会!
InnoDB是MySQL中的一种存储引擎,他会为每个表创建一个主键索引。如有没有明确的主键索引,InnoDB会使用一个隐藏。自动生成的主键来创建索引。这个隐藏的主键索引使用的就是B+树结构,在InnoDB中,即使表没有明确的主键索引,也会创建一个B+树索引。

(六)、Hash索引

Hash索引其实用的不多,最主要是因为常见的存储引擎InnoDB不支持显示地创建Hash索引,只支持自适应Hash索引 。
虽然可以使用sql语句在InnoDB显示声明Hash索引,但是其实是不生效的
在这里插入图片描述
对name字段建立Hash索引,但是通过 show index from 表名就会发现实际还是B+树
在这里插入图片描述
在存储引擎中,Memory引擎支持Hash索引:
Hash索引其实有点像java中的HashMap底层的数据结构,他也有很多的槽,存的也是键值对,键值为索引列,值为数据的这条数据的行指针,通过行指针就可以找到数据
假设现在user表Memory存储引擎,对name字段建立Hash索引,表中插入三条数据
在这里插入图片描述
Hash索引会对索引列name的值进行Hash计算,然后找到对应的槽下面,如下图所示
在这里插入图片描述
当遇到name字段的Hash值相同时,也就是Hash冲突,就会形成一个链表,比如有name=张三有有两条数据,机会想成一个链表。
之后如果要查name=李四的数据,只需要对李四进行Hash计算,找到对应的槽,遍历链表,取出name=李四对应的行指针,然后根据行指针去查对应的数据。
Hash索引优缺点:
a.Hash索引只能用于等值比较,所以查询效率非常高
b.不支持范围查询,也不支持排序,因为索引列的分布是无序的

(七)、聚集索引(局簇索引)、非聚集索引区别

按物理存储分类:聚集索引、非聚集索引(可以认为InnoDB的存储方式是聚集索引,MyISAM的存储方式是非聚集索引)
在这里插入图片描述
在这里插入图片描述

聚集索引并不是一个单独的索引类型,实际上是一种数据存储的方式。聚集索引的实现细节各有不同,在InnoDB引擎中,聚集索引实际上是将索引和数据行使用同样的结构存储在一个二叉树中。

如果数据表中有聚集索引,则数据行实际上是存在所有的叶子节点。“聚集”的形式实际是指相邻键值的数据行是邻近存储的。因为一行数据不能存储在两个叶子节点上,因此在数据表中只能有一个聚集索引。由于是存储引擎负责索引的实现,因此并不是全部的存储引擎都支持聚集索引。在这里我们只讨论InnoDB,但支持聚集索引的存储引擎实现聚集索引的原理都大同小异

下图展示了数据记录在聚集索引的存储布局。注意,叶子节点包含了完整的数据行,而其他节点仅仅只有索引。在这个图中,索引列使用的是整数。
在这里插入图片描述
有些数据库服务器允许我们选择对哪个索引进行聚集,但MySQL的任意内置的存储引擎都不支持这么做。InnoDB使用主键对数据进行聚集,这意味着上图的索引列实际上是主键列。
如果数据表没有定义主键,InnoDB会选择使用唯一的非空列(Not Null)索引替代。如果没有这样的索引,InnoDB会定义一个隐藏的主键去完成数据聚集**(因此,数据表最好自己定义主键)**。InnoDB的只能在一个数据页中进行数据聚集,因此即便是临近的索引值的数据存储页也可能间隔很远。
一个聚集主键能够提高性能,但同样也可能导致严重的性能问题。因此,你应当谨慎考虑聚集的使用,尤其是当你将一个数据表的存储引擎从InnoDB改为其他引擎时。

(a)、聚集索引具有如下的优势

1.提升检索效率:通过将表中的记录按照索引的顺序进行排序,聚集索引可以更快地进行数据检索,提升查询效率。
2.降低磁盘I/O操作:聚集索引由于将表中数据物理上存储在同一块磁盘区域,降低了磁盘I/O操作的开销,进而提高数据库的性能。
3.聚集索引的物理排序可以为某些表的查询提供帮助:例如,对于需要按照时间或者数值等规则进行排序或做范围查找操作时,聚集索引可以提高数据检索效率。

总之,聚集索引对于缩短数据检索时间和提高数据库性能非常重要,但在使用时需要根据具体应用需求进行权衡和调整。

(b)、聚集索引的缺点包括

1.一次只能创建一个聚集索引:每个表只能创建一个聚集索引,而不是多个,因此在不同的情况下需要根据具体应用需求进行合理选择。

2.聚集索引会随着数据的变化而产生碎片:当对表中的数据进行插入、删除或更新时,聚集索引的物理排序可能会发生变化,导致产生碎片,需要定期维护和重建。

3.修改和插入操作代价较高:当聚集索引的键发生变化时,数据库需要重新进行排序和存储,因此修改和插入操作的代价较高。

4.索引占用更多的空间:聚集索引对于数据的物理排序需要存储额外的信息,因此它所占用的磁盘空间比非聚集索引更大。

  • 索引可能会降低性能:有时候使用聚集索引并不一定会提高性能,甚至可能会降低性能。例如,聚集索引排序的方式可能与具体查询的方式不匹配,导致查询效率下降。

综上所述,虽然聚集索引可以大大提高查询效率,但在一些场景下可能会带来一定的负面影响。因此,在使用聚集索引时需要根据数据表的大小、查询方式和修改操作的频率等因素进行综合考虑和取舍。

(c)、非聚集索引

非聚集索引(Non-Clustered Index)是一种常见的数据库索引类型,与聚集索引不同的是,非聚集索引并不改变表中数据的物理存储方式。

非聚集索引通过创建一个独立的数据结构来记录索引值以及指向与该索引相关的行的指针,从而加速数据的检索。在非聚集索引的建立过程中,数据库会在磁盘上创建索引文件,其中记录了索引值和行指针的映射关系。

与聚集索引不同,每个表可以拥有多个非聚集索引,每个非聚集索引都有自己的结构,可以包含表中的一部分数据。非聚集索引通常可以加快查询效率,提高数据库的性能。

需要注意的是,更新表中数据时,非聚集索引将会耗费更多的时间和磁盘空间来维护。因为对于每一个数据行的插入、更新、删除操作都会导致非聚集索引的更新和维护。

总的来说,非聚集索引可以提高查询效率,但是对于修改操作需要更多的时间和磁盘空间支持。在实际应用中,需要根据查询和修改操作的特点,考虑使用哪种类型的索引。

(d)、非聚集索引的有点包括

不改变数据表的物理存储格式:与聚集索引不同,非聚集索引并不改变数据表的物理存储格式,因此对于数据表的插入、删除和更新操作的影响较小。

可以创建多个索引:每个数据表可以创建多个非聚集索引,每个非聚集索引都有自己的结构,可以包含表的一部分数据,并且可以被不同的查询使用,从而进一步提高查询效率。

数据表可以被多个非聚集索引覆盖:如果某个查询涉及到表的多个列,可以设置覆盖索引来避免查询需要访问数据表,从而提高查询效率。

能够加速特定的查询:非聚集索引可以根据列值、列的组合或表达式快速查找记录,针对特定的查询可以提高查询效率。

综上所述,非聚集索引可以提高查询效率,且对数据表的插入、删除和更新操作的影响较小,因此在实际应用中,根据查询和修改操作的特点,结合查询和修改操作的比重及数据表的大小等因素,可以考虑使用非聚集索引来优化数据库性能。

(e)、聚集索引的非聚集索引的区别

聚集索引和非聚集索引在数据库中起着不同的作用,它们的主要区别在于:

物理存储方式不同:聚集索引的数据行的物理存储顺序与索引的排序顺序相同,因此每张表只能有一个聚集索引。而非聚集索引的数据行的物理存储顺序与索引的排序顺序无关,因此每张表可以有多个非聚集索引。

插入、删除和更新操作时的影响不同:对于聚集索引,由于数据行的物理存储顺序与索引的排序顺序相同,因此在进行插入、删除和更新操作时需要对数据行的物理位置进行修改,这会对索引和数据表的性能造成一定的影响。而对于非聚集索引,它只存储了索引值和记录指针之间的映射关系,因此在进行插入、删除和更新操作时,只需要修改非聚集索引中的映射关系即可,对数据表的性能影响相对较小。

查询时的性能不同:聚集索引可以直接定位到数据行,因此在查询单条记录时有较好的性能表现。而非聚集索引需要先定位到索引,然后再通过记录指针查找数据行,因此在查询多条记录时会有一定的性能损失。

对内存的使用不同:由于聚集索引的所有数据行都按照索引的排序顺序存储,因此可以被缓存在内存中,以提高查询效率。而非聚集索引只存储了映射关系,无法完全缓存在内存中,因此查询效率相对而言较低。

综上所述,聚集索引和非聚集索引在数据库中的作用及特点是不同的。数据库设计时需要根据数据表的特点和查询需求来选择适合的索引类型。聚集索引适合于少量大批量的单行查询,而非聚集索引适合于多条件、大批量的查询。

(八)、二级索引(辅助索引)

二级索引又称为辅助索引,是因为二级索引的叶子节点存储的数据是主键。也就是说,通过二级索引,可以定位主键的位置

唯一索引,普通索引,前缀索引等索引属于二级索引。

a.**唯一索引(Unique Key) :**唯一索引也是一种约束。唯一索引的属性列不能出现重复的数据,但是允许数据为 NULL,一张表允许创建多个唯一索引。 建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。
b.**普通索引(Index) :**普通索引的唯一作用就是为了快速查询数据,一张表允许创建多个普通索引,并允许数据重复和 NULL。
c.**前缀索引(Prefix) :**前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小, 因为只取前几个字符。
d.**全文索引(Full Text) :**全文索引主要是为了检索大文本数据中的关键字的信息,是目前搜索引擎数据库使用的一种技术。Mysql5.6 之前只有 MYISAM 引擎支持全文索引,5.6 之后 InnoDB 也支持了全文索引。

在这里插入图片描述
在这里插入图片描述
在Mysql中主键索引的叶子节点存储的事整行的数据,而二级索引叶子节点内容是主键的值。

回表
讲完二级索引,接下来讲一讲如何使用二级索引查找数据。
这里假设对name字段创建了一个索引,并且表里就存了上面示例中的几条数据,这里我
再把图拿过来。

例如执行下面这条sql则需要进行回表:
在这里插入图片描述
在这里插入图片描述
由于查询条件是name =赵六,所以会走name索引
整个过程大致分为以下几个步骤:
1.从根节点开始,21<35定位右边存储指针
2.在索叶子节点找到35的第一条记录,也就是id=9的那条
3.由于是 select *,还要查其它字段,此时就会根据id=9到聚簇索(主键索引)中查找其它字段数据,这个查找过程前面说了很多次了,这个根据id=4到聚簇索引中查找数据的过程就被称为回表

(九)、覆盖索引

上一节说当执行 select * from user where age = 35;这条sql的时候,会先从索引页中查出来age = 35;对应的主键id,之后再回表,到聚簇索引中查询其它字段的值。
那么当执行下面这条sql,又会怎样呢?
在这里插入图片描述
这次查询字段从 select * 变成 select id,查询条件不变,所以也会走age索引
在这里插入图片描述
所以还是跟前面一样了,先从索引页中查出来age = 35;对应的主键id之后,惊讶的发现,sql中需要查询字段的id值已经查到了,那次此时压根就不需要回表了,已经查到id了,还回什么表。
而这种需要查询的字段都在索引列中的情况就被称为覆盖索引,索引列覆盖了查询字段的意思。
当使用覆盖索引时会减少回表的次数,这样查询速度更快,性能更高。
所以,在日常开发中,尽量不要select *需要什么查什么,如果出现覆盖索引的情况,查询会快很多。

(十)、索引下推

索引下推(INDEX CONDITION PUSHDOWN,简称ICP)是在MySQL 5.6 针对扫描二级索引的一项优化改进。用来在范围查询时减少回表的次数。ICP 适用于 MYISAM和INNODB。
在这里插入图片描述
不使用索引下推实现
在这里插入图片描述
使用索引下推实现
在这里插入图片描述
①.MySQL中的server层首先调用存储引擎定位到第一个以"A"开头的Name;

②.找到记录后,存储引擎并不急着回表,而是继续在存储引擎中判断这条记录的Age是否为40,如果是,再去回表查询完整的记录;如果不是,不去回表了,直接继续读取下一条记录;

③.存储引擎将符合条件的数据返回给server层,此时如果还有其他非索引的查询条件,server层继续过滤,在上面的案例中,此时没有其他查询条件了,server层将最终的数据返回给客户端.假设server层还有其他的查询条件,并且这个查询条件把刚刚查到的记录过滤掉了,那么就会通过该记录中的next_record属性读取下一条记录,然后重复第②步;

这就是索引下推(Index Condition Pushdown,ICP),有效的减少了回表次数,提高了查询效率!

(十一)、单列索引、组合索引(最左前缀原则)

(一)、单列索引

在这里插入图片描述
假设,我们现在对name字段加了一个普通非唯一索引,那么name就是索引列,同时name这个索引也就是单列索引
此时如果往表中插入三条数据,那么name索引的叶子节点存的数据就如下图所示
在这里插入图片描述
mysql会根据name字段的值进行排序,这里我假设张三排在李四前面,当索引列的值相
同时,就会根据id排序,所以索引实际上已经根据索引列的值排好序了

这里肯定有小伙伴疑问,name字段存储的中文也可以排序么?
答案是可以的,并且mysql支持很多种排序规则,我们在建数据库或者是建表的时候等都可以指定排序规则,并且后面文章涉及到的字符串排序都是我随便排的,实际情况可能不一样。
在这里插入图片描述
对于单个索引列数据查找也是跟前面说的聚簇索引一样,也会对数据分组,之后可以根据分查找在单个索引列来查找数据。
当数据不断增多,一个索引页存储不下数据的时候,也会用多个索引页来存储,并且索引页直接也会形成双向链表如图所示:
在这里插入图片描述
当索引页不断增多是,为了方便在不同索引页中查找数据,也就会抽取一个索引页,除了存页中id,同时也会存储这个id对应的索引列的值
在这里插入图片描述
当数据越来越多越来越多,还会抽取,也会形成三层的一个B+树,这里我就不画了。

(二)、联合索引

在这里插入图片描述
除了单列索引,联合索引其实也是一样的,只不过索引页存的数据就多了一些索引列
比如,在name和age上建立一个联合索引,此时单个索引页就如图所示
在这里插入图片描述

先以name排序,name相同时再以age排序,如果再有其它列,依次类推,最后再以id排序。
相比于只有name一个字段的索引来说,索引页就多存了一个索引列。最后形成的B+树简化为如下图
在这里插入图片描述

最左前缀原则
顾名思义是最左优先,以最左边的为起点任何连续的索引都能匹配上
如果没有第一列的话,直接访问第二列,那第二列肯定是无序的,直接访问后面的列就用不到索引了
当创建(a,b,c)复合索引时,想要索引生效的话,只能使用 a、ab和abc三种组合!

(三)、联合索引的优势

1.减小开销
建一个联合索引(a,b,c),实际相当于建了(a),(a,b),a,b,c)三个索引每多一个索引,都会增加写操作的开销和磁盘空间的开销.对于大量数据的表使用联合索引会大大的减少开销!
2.覆盖索引
对联合索引(a,b,c)如果有如下sql的 select a,b,c from table where a=‘xxx’ and b=‘xx’;
那么mysql可以直接通过遍历索引取得数据而无需回表,这减少了很多的随机io操作.减少io操作特别是随机io其实DBA主要的优化策略.所以在真正的实际应用中覆盖索引是主要的提升性能的优化手段之一。
3.效率高
索引列多通过联合索引筛选出的数据越少比如有1000w条数据的表有如下sql:
select col1,col2,col3 from table where col1=1 and col2=2 and col3=3;
假设:假设每个条件可以筛选出10%的数据
A:如果只有单列索引那么通过该索引能筛选出1000w10%=100w条数据然后再回表从100w调数据
中找到符合col2=2 and col3=3的数据然后再排序再分页以此类推(递归)
B:如果是(col1,col2,col3)联合索引,通过三列索引筛选出1000w
10%*10%*10%=1w,效率提升可想而知!

(四)、优缺点

优点:
1.提高检索效率
2.降低排序成本,索引对应的字段是会有一个自动排序功能的,默认是升序asc。
缺点:
1.创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
2.索引需要占用物理空间,数据量越大,占用空间越大
3.会降低表的增删改的效率,因为每次增删改索引,都需要进行动态维护

竟然索引有坏有好,什么时候需要索引,什么时候不需要?
适合
1.较频繁的作为查询条件的字段应该创建索引
不适合
1.字段值的唯一性太差不适合单独做索引
2.更新非常频繁的字段不适合
3.不会出现在where何中的字段不适合

四、索引优化

(一)、全值匹配

(二)、最左前缀原则

(三)、索引列上少计算数

不在索引列上做任何操作(计算、函数、(自动or手动)类型转换 ),会导致索引失效而转向全表扫描
在这里插入图片描述
在这里插入图片描述
sql2:在每个name上做计算,所以全表扫描了

(四)、范围后面全失效

在这里插入图片描述

(五)、覆盖索引不写星

(六)、不等空值还有or,索引失效要少用

(七)、Like百分写最右

(八)、VAR引号不可丢

(九)、范围查询优化

在这里插入图片描述

(十)、索引总结

全值匹配我最爱,最左前缀要遵守;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围之后全失效;
Like百分写最右,覆盖索引不写星;
不等空值还有or,索引失效要少用;
VAR引号不可丢,SQL高级也不难!

五、trace工具

trace是MySQL5.6版本后提供的SQL跟踪工具,通过使用trace可以让我们明白optimizer(优化器)如何选择执行计划。
注意:开启trace工具会影响mysql性能,所以只适合临时分析sql使用,用完之后请立即关闭。

语法:

-- 1,打开trace,设置格式为JSON,设置trace的缓存大小,避免因为容量大小而不能显示完整的跟踪过程。
set optimizer_trace="enabled=on",end_markers_in_JSON=on;
-- 2,执行想做trace的SQL语句
select * from t_pay_order_info where biz_code = 'B202305220001' and biz_order_code = 'B202305220002';
-- 3,查询information_schema.optimizer_trace,可以看到跟踪记录了
select * from information_schema.optimizer_trace;

在这里插入图片描述
说明:

{
  "steps": [
    {
      "join_preparation": {  -- 第一阶段:SQL准备阶段,格式化sql
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `t_student`.`id` AS `id`,`t_student`.`std_name` AS `std_name`,`t_student`.`age` AS `age`,`t_student`.`class_id` AS `class_id`,`t_student`.`gmt_create` AS `gmt_create` from `t_student` where (`t_student`.`std_name` > 'a') order by `t_student`.`age`"
          }
        ] /* steps */
      } /* join_preparation */
    },
    {
      "join_optimization": {  -- 第二阶段:SQL优化阶段
        "select#": 1,
        "steps": [
          {
            "condition_processing": {  -- 条件处理
              "condition": "WHERE",
              "original_condition": "(`t_student`.`std_name` > 'a')",
              "steps": [
                {
                  "transformation": "equality_propagation",
                  "resulting_condition": "(`t_student`.`std_name` > 'a')"
                },
                {
                  "transformation": "constant_propagation",
                  "resulting_condition": "(`t_student`.`std_name` > 'a')"
                },
                {
                  "transformation": "trivial_condition_removal",
                  "resulting_condition": "(`t_student`.`std_name` > 'a')"
                }
              ] /* steps */
            } /* condition_processing */
          },
          {
            "substitute_generated_columns": {
            } /* substitute_generated_columns */
          },
          {
            "table_dependencies": [  -- 表依赖详情
              {
                "table": "`t_student`",
                "row_may_be_null": false,
                "map_bit": 0,
                "depends_on_map_bits": [
                ] /* depends_on_map_bits */
              }
            ] /* table_dependencies */
          },
          {
            "ref_optimizer_key_uses": [
            ] /* ref_optimizer_key_uses */
          },
          {
            "rows_estimation": [  -- 预估表的访问成本
              {
                "table": "`t_student`",
                "range_analysis": {
                  "table_scan": {   -- 全表扫描
                    "rows": 100300,  -- 行数
                    "cost": 20351  -- 查询消耗
                  } /* table_scan */,
                  "potential_range_indexes": [  -- 查询可能使用的索引
                    {
                      "index": "PRIMARY",  -- 主键索引
                      "usable": false,  -- 未使用
                      "cause": "not_applicable"  -- 原因:不适合
                    },
                    {
                      "index": "idx_std_age",  -- age索引
                      "usable": false,  -- 未使用
                      "cause": "not_applicable"  -- 原因:不适合
                    },
                    {
                      "index": "idx_std_name_age_class",  -- stdname,age,class的组合索引
                      "usable": true,  -- 使用
                      "key_parts": [
                        "std_name",
                        "age",
                        "class_id",
                        "id"
                      ] /* key_parts */
                    }
                  ] /* potential_range_indexes */,
                  "setup_range_conditions": [
                  ] /* setup_range_conditions */,
                  "group_index_range": {  -- group 用到的索引
                    "chosen": false,  -- 未使用
                    "cause": "not_group_by_or_distinct"  -- 原因:未使用group by 或者 distinct
                  } /* group_index_range */,
                  "analyzing_range_alternatives": {   -- 分析各个索引使用成本
                    "range_scan_alternatives": [
                      {
                        "index": "idx_std_name_age_class",
                        "ranges": [
                          "a < std_name"  -- 索引使用范围
                        ] /* ranges */,
                        "index_dives_for_eq_ranges": true,
                        "rowid_ordered": false,  -- 使用该索引获取的记录是否按照主键排序
                        "using_mrr": false,
                        "index_only": false,  -- 是否使用覆盖索引
                        "rows": 50150,  -- 索引扫描行数
                        "cost": 60181,   -- 索引使用成本
                        "chosen": false,  -- 是否选择该索引:否
                        "cause": "cost"  -- 原因:消耗
                      }
                    ] /* range_scan_alternatives */,
                    "analyzing_roworder_intersect": {  -- 分析使用索引合并的成本
                      "usable": false,
                      "cause": "too_few_roworder_scans"
                    } /* analyzing_roworder_intersect */
                  } /* analyzing_range_alternatives */
                } /* range_analysis */
              }
            ] /* rows_estimation */
          },
          {
            "considered_execution_plans": [  -- 分析出的执行计划
              {
                "plan_prefix": [
                ] /* plan_prefix */,
                "table": "`t_student`",
                "best_access_path": {  -- 最优访问路径
                  "considered_access_paths": [  --分析出的最终访问路径
                    {
                      "rows_to_scan": 100300,
                      "access_type": "scan",  -- 访问类型:为scan,全表扫描
                      "resulting_rows": 100300,
                      "cost": 20349,
                      "chosen": true,  -- 确定选择
                      "use_tmp_table": true
                    }
                  ] /* considered_access_paths */
                } /* best_access_path */,
                "condition_filtering_pct": 100,
                "rows_for_plan": 100300,
                "cost_for_plan": 20349,
                "sort_cost": 100300,
                "new_cost_for_plan": 120649,
                "chosen": true
              }
            ] /* considered_execution_plans */
          },
          {
            "attaching_conditions_to_tables": {   -- 为查询的表添加条件
              "original_condition": "(`t_student`.`std_name` > 'a')",
              "attached_conditions_computation": [
              ] /* attached_conditions_computation */,
              "attached_conditions_summary": [    -- 添加条件结果
                {
                  "table": "`t_student`",
                  "attached": "(`t_student`.`std_name` > 'a')"
                }
              ] /* attached_conditions_summary */
            } /* attaching_conditions_to_tables */
          },
          {
            "clause_processing": {   -- order by 处理
              "clause": "ORDER BY",
              "original_clause": "`t_student`.`age`",
              "items": [
                {
                  "item": "`t_student`.`age`"
                }
              ] /* items */,
              "resulting_clause_is_simple": true,
              "resulting_clause": "`t_student`.`age`"
            } /* clause_processing */
          },
          {
            "reconsidering_access_paths_for_index_ordering": {    -- 重构索引处理顺序
              "clause": "ORDER BY",
              "steps": [
              ] /* steps */,
              "index_order_summary": {
                "table": "`t_student`",
                "index_provides_order": false,
                "order_direction": "undefined",
                "index": "unknown",
                "plan_changed": false
              } /* index_order_summary */
            } /* reconsidering_access_paths_for_index_ordering */
          },
          {
            "refine_plan": [
              {
                "table": "`t_student`"
              }
            ] /* refine_plan */
          }
        ] /* steps */
      } /* join_optimization */
    },
    {
      "join_execution": {    -- 第三阶段:SQL执行阶段
        "select#": 1,
        "steps": [
          {
            "filesort_information": [
              {
                "direction": "asc",
                "table": "`t_student`",
                "field": "age"
              }
            ] /* filesort_information */,
            "filesort_priority_queue_optimization": {
              "usable": false,
              "cause": "not applicable (no LIMIT)"
            } /* filesort_priority_queue_optimization */,
            "filesort_execution": [
            ] /* filesort_execution */,
            "filesort_summary": {
              "rows": 100000,
              "examined_rows": 100000,
              "number_of_tmp_files": 14,
              "sort_buffer_size": 262016,
              "sort_mode": "<sort_key, packed_additional_fields>"
            } /* filesort_summary */
          }
        ] /* steps */
      } /* join_execution */
    }
  ] /* steps */
}

六、sql优化

(一)、不要写select *

(二)、小表驱动大表

(三)、连接查询代替子查询

(四)、提升group by 的效率

(五)、批量插入

(六)、使用Limit

(七)、nuion all 代替 union

(八)、尽量少关联表

  • 7
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值