❤️吐血总结《MySQL从入门到成神》,图文并茂(建议收藏)❤️

Posted Java程序鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了❤️吐血总结《MySQL从入门到成神》,图文并茂(建议收藏)❤️相关的知识,希望对你有一定的参考价值。

💂 个人主页: Java程序鱼
🤟 准备精心打造一套精品MySQL课程,大家可以持续关注
💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦
💅 有任何问题欢迎私信,看到会及时回复!

序号内容链接地址
0mysql面试题https://blog.csdn.net/qq_35620342/article/details/119930887
1MySQL基础总结https://blog.csdn.net/qq_35620342/article/details/120081524
2MySQL索引待分享
3MySQL事务待分享
4MySQL锁机制待分享
5MySQL日志(redo log、undo log、binlog)待分享
6主从复制原理待分享
7主从延迟解决方案待分享
8SQL语句查询原理待分享
9MySQL海量数据优化待分享
10SQL优化待分享
11数据库与缓存双写一致性方案待分享
12分布式锁待分享


一、索引是什么?

  • 索引是存储引擎用于快速检索记录行的一种数据结构,用于提升数据库的查找速度。
  • 索引一般存储在磁盘的文件中,它是占用物理空间的。
  • 适当的索引能提高查询效率,过多的索引会影响数据库表的插入和更新性能

为什么需要使用索引:

①索引能极大的减少存储引擎需要扫描的数据量

②索引可以把随机I/O变为顺序I/O

③索引可以帮助我们进行分组、排序等操作时,避免使用临时表

索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对性能的影响愈发重要,在数据量较小且负载较低时,不恰当的索引对性能的影响可能还不明显,但当数据量逐渐增大时,性能则会急剧下降。

索引优化应该是查询性能优化最有效的手段了(可以起到立竿见影的效果),索引能够轻易将查询性能提高几个数量级,’最优’的索引有时比一个‘好的’索引性能要好两个数量级,创建一个真正’最优’的索引经常需要重写查询。

二、索引有哪些类型?

1.数据结构维度

(1)B+树索引:所有数据存储在叶子节点,复杂度为O(logn),适合范围查询。

(2)哈希索引: 适合等值查询,检索效率高。

哈希索引基于哈希表实现,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希码是一个较小的值,并且不同键值的行计算出来的哈希码也不一样。哈希索引将所有的哈希码存储在索引中,同时在哈希表中保存指向每个数据行的指针。

但是范围查找不适合,因为存储引擎都会为每一行计算一个hash码,hash码都是比较小的,并且不同键值行的hash码通常是不一样的,hash索引中存储的就是Hash码,hash 码彼此之间是没有规律的,且 Hash 操作并不能保证顺序性,所以值相近的两个数据,Hash值相差很远,被分到不同的桶中。这就是为什么hash索引只能进行全职匹配的查询,因为只有这样,hash码才能够匹配到数据。

在MySQL中,只有Memory引擎显示支持哈希索引,这是Memory引擎的默认索引,Memory引擎同时也支持B-Tree索引,指得一提的是,Memory引擎是支持非唯一哈希索引的,如果多个列的哈希值相同,索引会以链表的方式存放多个记录指针到同一个哈希条目中。HASH时间复杂度O(1),链表时间复杂度是O(n)

InnoDB支持Hash索引吗?

  • InnoDB用户无法手动创建哈希索引,这一层上说,InnoDB确实不支持哈希索引;
  • InnoDB会自调优(self-tuning),如果判定建立自适应哈希索引(Adaptive Hash Index, AHI),能够提升查询效率,InnoDB自己会建立相关哈希索引,这一层上说,InnoDB又是支持哈希索引的;

(3)全文索引:只能在文本类型CHAR,VARCHAR,TEXT类型字段上创建全文索引。字段长度比较大时,如果创建普通索引,在进行like模糊查询时效率比较低,这时可以创建全文索引。 MyISAM和InnoDB中都可以使用全文索引。

2.物理存储维度

(1)聚簇索引(主键索引):每个InnoDB表都有一个聚簇索引 ,聚簇索引使用B+树构建,叶子节点存储的数据是整行记录。一般情况下,聚簇索引等同于主键索引,当一个表没有创建主键索引时,InnoDB会自动创建一个ROWID字段来构建聚簇索引。InnoDB创建索引的具体规则如下:

  • 如果表定义了PK,则PK就是聚集索引;
  • 如果表没有定义PK,则第一个非空unique列是聚集索引;
  • 否则,InnoDB会创建一个隐藏的row-id作为聚集索引;

(2)非聚簇索引(二级索引):非聚簇索引就是以非主键创建的索引,叶子节点存储的是主键和索引列。

3.逻辑维度

(1)主键索引:主键索引一般都是在创建表的时候指定,「一个表只有一个主键索引」,特点是「唯一、非空」。

(2)普通索引:普通索引唯一的作用就是加快查询。

(3)组合索引:组合索引是创建一个「多个字段的索引」,这个概念是相对于上上面的单列索引而言,组合索引查询遵循「最左前缀原则」。

(4)唯一索引:唯一索引具有的特点就是唯一性,可以在创建表的时候指定,也可以在创建表后创建。

(5)空间索引:MySQL在5.7之后的版本支持了空间索引,而且支持OpenGIS几何数据模型。MySQL在空间索引这方面遵循OpenGIS几何数据模型规则。

三、为什么选择B+树作为索引结构?

可以从几个维度去看这个问题,查询是否够快,效率是否稳定,存储数据多少,以及查找磁盘次数,为什么不是二叉树,为什么不是平衡二叉树,为什么不是B树,而偏偏是B+树呢?

1.为什么不使用哈希结构?

我们知道哈希结构,类似k-v结构,也就是,key和value是一对一关系。它用于「等值查询」还可以,但是范围查询它是无能为力的哦。

2.为什么不使用二叉树呢?

  • 当数据量大时,树的高度会比较高(树的高度决定着它的IO操作次数,IO操作耗时大),查询会比较慢。
  • 每个磁盘块(节点/页)保存的数据太小(IO本来是耗时操作,每次IO只能读取到一个关键字,显然不合适)
  • 如果二叉树特殊化为一个链表,相当于全表扫描

没有很好的利用操作磁盘IO的数据交换特性,也没有利用好磁盘IO的预读能力(空间局部性原理),从而带来频繁的IO操作。

3.为什么不使用B树呢?

B树的搜索:从根节点开始,对节点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子节点;重复,直到所对应的儿子指针为空,或已经是叶子节点。 关键字集合分布在整颗树中 ,即叶子节点和非叶子节点都存放数据,搜索可能在非叶子节点结束。其搜索性能等价于在关键字全集内做一次二分查找。

假设检索26,先把磁盘块1加载到内存中,然后26与28和46比较,26比28小,然后基于P1子节点引用,P1是指向磁盘块2的一个指针地址,基于P1引用可以通过顺序IO快速加载磁盘块2,然后26与19和23比,26大于23,通过P3子节点引用,加载磁盘块7。然后命中,基于节点数据区加载数据。

B树的特点:

  • 不再是二叉搜索,而是m叉搜索;
  • 叶子节点,非叶子节点,都存储数据;
  • 中序遍历,可以获得所有节点;

名词解释:

局部性原理:软件设计要尽量遵循 “数据读取集中”与“使用到一个数据,大概率会使用其附近的数据”,这样磁盘预读能充分提高磁盘IO;

磁盘预读能力:磁盘读写并不是按需读取,而是按页预读,一次会读一页的数据,每次加载更多的数据,如果未来要读取的数据就在这一页中,可以避免未来的磁盘IO,提高效率;

数据交换特性:操作系统去硬盘读取一次,做一次I/O交换,一次交换数据是4k(Linux默认页大小),交换单位以页为单位,1页就是4k(索引按数据页为单位读写的,在InnoDB中,每个数据页的大小默认是16KB)

3.为什么使用B+树?

它是B-Tree数的变体,也是一种多路搜索树B+Tree和B-Tree基本相同,区别在于B-Tree树非叶子节点和叶子节点都可以存放数据,而B+Tree树关键字存储在叶子节点上,非叶子节点不存真正的数据。(B+树中根到每一个节点的路径长度一样,因此查询速度更稳定;而B树不是这样)

叶子之间,增加了链表,获取所有节点,不再需要中序遍历,直接遍历叶子节点就行;

比如查找28,其实图顶端的28是索引,并不是真实数据,他会继续往下找。

B+Tree与B-Tree比较

①B+Tree范围查找,定位min与max之后,中间叶子节点,就是结果集,不用中序回溯;

②B+Tree磁盘读写能力更强(叶子节点不保存真实数据,因此一个磁盘块能保存的关键字更多,因此每次加载的关键字越多)

③B+Tree扫表和扫库能力更强(B-Tree树需要扫描整颗树,B+Tree树只需要扫描叶子节点)

四、B+树索引搜索过程

准备数据:

CREATE TABLE `employee` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `date` datetime DEFAULT NULL,
  `sex` int(1) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_age` (`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into employee values(1,'小红',43,'2021-01-20','0');
insert into employee values(2,'铁蛋',48,'2021-01-21','0');
insert into employee values(3,'张三',36,'2020-01-21','1');
insert into employee values(4,'李四',32,'2020-01-21','0');
insert into employee values(5,'王老五',37,'2020-01-21','1');
insert into employee values(6,'赵六',49,'2021-01-21','0');
insert into employee values(7,'小丑',28,'2021-01-21','1');

索引结构图:


(1)非聚簇索引(二级索引)

select * from employee where age=32;

这条 SQL 查询语句执行流程:

  • 搜索idx_age索引树,将磁盘块1加载到内存,由于32<37,搜索左路分支,到磁盘寻址磁盘块2。
  • 将磁盘块2加载到内存中,在内存继续遍历,找到age=32的记录,取得id = 4.
  • 拿到id=4后,回到id主键索引树。
  • 搜索id主键索引树,将磁盘块1加载内存,在内存遍历,找到了4,但是B+树索引非叶子节点是不保存数据的。索引会继续搜索4的右分支,到磁盘寻址磁盘块3.
  • 将磁盘块3加载内存,在内存遍历,找到id=4的记录,拿到R4这一行的数据,好的,大功告成。

什么是回表查询呢?回表查询简单来说「通过二级索引查询数据,得不到完整的数据行,只能拿到主键ID,需要再次查询主键索引来获得数据行」。

(2)聚簇索引(主键索引)

select * from employee where id = 4;

这条 SQL 查询语句执行流程:

  • 搜索id主键索引树,将磁盘块1加载内存,在内存遍历,找到了4,但是B+树索引非叶子节点是不保存数据的。索引会继续搜索4的右分支,到磁盘寻址磁盘块3.
  • 将磁盘块3加载内存,在内存遍历,找到id=4的记录,拿到R4这一行的数据,好的,大功告成。

五、覆盖索引

大家想一个问题,如果不用select *, 而是使用select id,age,执行几次树搜索操作呢?

select id,age from employee where age=32;

这条 SQL 查询语句执行流程:

  • 搜索idx_age索引树,将磁盘块1加载到内存,由于32<37,搜索左路分支,到磁盘寻址磁盘块2。
  • 将磁盘块2加载到内存中,在内存继续遍历,找到age=32的记录,取得id = 4.
  • 拿到id=4后,id和age的值都有了,此时就不会去主键索引树查询了

覆盖索引:在查询的数据列里面,不需要回表去查,直接从索引列就能取到想要的结果。换句话说,你SQL用到的索引列数据,覆盖了查询结果的列,就算上覆盖索引了。

六、索引哪些情况会失效?

  • 查询条件包含or,会导致索引失效。
  • 隐式类型转换,会导致索引失效,例如age字段类型是int,我们where age = “1”,这样就会触发隐式类型转换。
  • like通配符会导致索引失效。注意:"ABC%“会走range索引,”%ABC"索引才会失效。
  • 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。
  • 对索引字段进行函数运算。
  • 对索引列运算(如,+、-、*、/),索引失效。
  • 索引字段上使用(!= 或者 < >,not in)时,会导致索引失效。
  • 索引字段上使用is null, is not null,可能导致索引失效。
  • 相join的两个表的字符编码不同,不能命中索引,会导致笛卡尔积的循环计算
  • mysql估计使用全表扫描要比使用索引快,则不使用索引。

我会在群里分享学习方法、学习资料、技术答疑

以上是关于❤️吐血总结《MySQL从入门到成神》,图文并茂(建议收藏)❤️的主要内容,如果未能解决你的问题,请参考以下文章

Kafka从入门到成神系列 五Kafka 幂等性及事务

Kafka从入门到成神系列 六Kafka 消费组及重平衡

零基础如何学习python?10本精品书籍从入门到成神!

操作系统入门到成神系列 二磁盘比内存慢几万倍?

❤️强烈推荐人工智能学习网站❤️

独家巨献!阿里专家兼Github贡献者,整理的SpringBoot入门到成神