回味,无味,余味。我,一名大三的无名之辈。Dino
文章目录
一、索引是什么?
MySQL官方对索引的定义为:1.索引(index)是帮助MySQL高效获取数据的数据结构(有序)。
2,数据之外,数据库系统还维护着特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据.
3. 在这些数据结构上实现高级查找算法,这种数据结构就是索引。
如下图所示:
----->最左边的是数据记录的物理地址
----->意逻辑上相邻的记录在磁盘上也并不是一定物理相邻的
----->为了加快Col2的查找,可以维护一个右边所示的二叉查找树
----->每个节点分别包含索引键值和一个指向对应数据记录物理地址的指针
----->这样可以运用二叉查找快速获取到相应数据
二、建立索引的优势和劣势
1.优势🌈
1.提高数据检索的效率,降低数据库的IO成本 😀
2.通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗 - -!😊
2.劣势🌈
1.索引也是一张表,保存了主键与索引字段并指向实体类的记录所以索引列也是要占用空间 😀
2.降低更新表的速度(INSERT、UPDATE、DELETE) ,更新表时,MySQL 不仅要保存数据,还要保存一下索引文件每次更新添加了索引列的字段,都会调整因为更新所带来的键值变化后的索引信息 😄
三、索引的结构
1.mysql包含的四种索引 🌂
:>BTREE 索引 : 最常见的索引类型,大部分索引都支持 B 树索引
:>HASH 索引:只有Memory引擎支持 , 使用场景简单
:>R-tree 索引(空间索引):空间索引是MyISAM引擎的一个特殊索引类型(很少使用)
:>Full-text (全文索引):全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引
注意:如果没有特别指明,都是指B+树(多路搜索树,并不一定是二叉的)结构组织的索引。其中聚集索引、复合索引、前缀索引、唯一索引默认都是使用 B+tree 索引,统称为 索引.😄
2. Btree 结构🌂
BTree又叫多路平衡搜索树,一颗m叉的BTree特性如下:
–> 树中每个节点最多包含m个孩子。
–> 除根节点与叶子节点外,每个节点至少有[ceil(m/2)]个孩子。
–> 若根节点不是叶子节点,则至少有两个孩子。
–> 所有的叶子节点都在同一层。
–> 每个非叶子节点由n个key与n+1个指针组成,其中[ceil(m/2)-1] <= n <= m-1
😄
示例:
以5叉BTree为例,key的数量:公式推导[ceil(m/2)-1] <= n <= m-1。所以 2 <= n <=4 。当n>4时,中间节点分裂到父节点,两边节点分裂。插入 C N G A H E K Q M F W L T Z D P R X Y S 数据为例。
1). 插入前4个字母 C N G A 🤭
2). 插入H,n>4,中间元素G字母向上分裂到新的节点 🤭
3). 插入E,K,Q不需要分裂 🤭
4). 插入M,中间元素M字母向上分裂到父节点G 🤭
5). 插入F,W,L,T不需要分裂 🤭
6). 插入Z,中间元素T向上分裂到父节点中 🤭
7). 插入D,中间元素D向上分裂到父节点中。然后插入P,R,X,Y不需要分裂 🤭
8). 最后插入S,NPQR节点n>5,中间节点Q向上分裂,但分裂后父节点DGMT的n>5,中间节点M向上分裂 🤭
该BTREE树就已经构建完成了, BTREE树 和 二叉树 相比, 查询数据的效率更高, 因为对于相同的数据量来说,BTREE的层级结构比二叉树小,因此搜索速度快
3.B+ Tree 结构 🌂
B+Tree为BTree的变种,B+Tree与BTree的区别为:
1). n叉B+Tree最多含有n个key,而BTree最多含有n-1个key。
2). B+Tree的叶子节点保存所有的key信息,依key大小顺序排列。
3). 所有的非叶子节点都可以看作是key的索引部分。
由于B+Tree只有叶子节点保存key信息,查询任何key都要从root走到叶子。所以B+Tree的查询效率更加稳定。
4. Mysql 中的B+Tree 的结构 🌂
在原B+Tree的基础上,增加一个指向相邻叶子节点的链表指针,就形成了带有顺序指针的B+Tree,提高区间访问的性能。
四、索引设计原则
1.对查询频次较高,且数据量比较大的表建立索引。😄
2.索引字段的选择,最佳候选列应当从where子句的条件中提取,如果where子句中的组合比较多,那么应当挑选最常用、过滤效果最好的列的组合。😄
3.使用唯一索引,区分度越高,使用索引的效率越高。 😄
4.索引可以有效的提升查询数据的效率,但索引数量不是多多益善,索引越多,维护索引的代价自然也就水涨船高。对于插入、更新、删除等DML操作比较频繁的表来说,索引过多,会引入相当高的维护代价,降低DML操作的效率,增加相应操作的时间消耗。另外索引过多的话,MySQL也会犯选择困难病,虽然最终仍然会找到一个可用的索引,但无疑提高了选择的代价。😄
5.使用短索引,索引创建之后也是使用硬盘来存储的,因此提升索引访问的I/O效率,也可以提升总体的访问效率。假如构成索引的字段总长度比较短,那么在给定大小的存储块内可以存储更多的索引值,相应的可以有效的提升MySQL访问索引的I/O效率。 😄
6.利用最左前缀,N个列组合而成的组合索引,那么相当于是创建了N个索引,如果查询时where子句中使用了组成该索引的前几个字段,那么这条查询SQL可以利用组合索引来提升查询效率。😄
创建复合索引:
CREATE INDEX idx_name_email_status ON tb_seller(NAME,email,STATUS);
就相当于
对name 创建索引 ;
对name , email 创建了索引 ;
对name , email, status 创建了索引 ;
五、避免索引失效
1). 全值匹配 ,对索引中所有列都指定具体值。⚡
explain select * from xxx where name='xx' and status='x' and address='xx
xx';
2).最左前缀法则 ⚡
如果索引了多列,要遵守最左前缀法则。指的是查询从索引的最左前列开始,并且不跳过索引中的列。
CREATE INDEX idx_name_email_status ON tb_customer(name,email,status);
#匹配最左走索引
explain select * from tb_customer where name =xxx and Email= xx x and status = xxx;
#违反最左不走索引
expain seelct * from tb_customer where email =xxxx and status =xxxx
3)不要在索引列上进行运算操作, 索引将失效。⚡
4). 范围查询右边的列,不能使用索引 .⚡
explain select * from tb_customer where name= xxx and status>1 and email xxxx
5). 字符串不加单引号,造成索引失效。 ⚡
由于,在查询是,没有对字符串加单引号,MySQL的查询优化器,会自动的进行类型转换,造成索引失效
6). 尽量使用覆盖索引,避免select * ⚡
尽量使用覆盖索引(只访问索引的查询(索引列完全包含查询列)),减少select * 。
如果查询列,超出索引列,也会降低性能。
7). 用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。示例,name字段是索引列 , 而createtime不是索引列,中间是or进行连接是不走索引的 ⚡
8). 以%开头的Like模糊查询,索引失效。⚡
如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。
9). 如果MySQL评估使用索引比全表更慢,则不使用索引。⚡
这句话怎么理解 :
----->比方说 在 city 这一列中 大部分都是 北京那么
----->select * from tb_ customer where city = ‘北京’ (标注: city 是索引列)
----->这条语句 是不会走索引的 .
10). is NULL , is NOT NULL 有时索引失效。 ⚡
11). in 走索引, not in 索引失效 ⚡
注意: 10 和 11 的失效的原因和9 一样 .
12). 单列索引和复合索引。 ⚡
创建复合索引 ⚡⚡
create index idx_name_sta_address on tb_seller(name, status, address);
就相当于创建了三个索引 :
name
name + status
name + status + address
创建单列索引 ⚡⚡
create index idx_seller_name on tb_seller(name);
create index idx_seller_status on tb_seller(status);
create index idx_seller_address on tb_seller(address);
数据库会选择一个最优的索引(辨识度最高索引)来使用,并不会使用全部索引 。
六、查看索引使用情况
show status like ‘Handler_read%’; 😄
show global status like ‘Handler_read%’; 😄
Handler_read_first:索引中第一条被读的次数。如果较高,表示服务器正执行大量全索引扫描(这个值越低越好)。🌹
Handler_read_key:如果索引正在工作,这个值代表一个行被索引值读的次数,如果值越低,表示索引得到的 性能改善不高,因为索引不经常使用(这个值越高越好)。🌹
Handler_read_next :按照键顺序读下一行的请求数。如果你用范围约束或如果执行索引扫描来查询索引列,该值增加。 🌹
Handler_read_prev:按照键顺序读前一行的请求数。该读方法主要用于优化ORDER BY … DESC。🌹
Handler_read_rnd :根据固定位置读一行的请求数。如果你正执行大量查询并需要对结果进行排序该值较高。你可能使用了大量需要MySQL扫描整个表的查询或你的连接没有正确使用键。这个值较高,意味着运行效率低,应该建立索引来补救。🌹
Handler_read_rnd_next:在数据文件中读下一行的请求数。如果你正进行大量的表扫描,该值较高。通常说明你的表索引不正确或写入的查询没有利用索引。🌹
其实,只有自己知道,你的野心。