MySQL 索引

MySQL索引

索引

索引就相当于一本书的目录,有了目录,就会大大增加查找的效率

但是有得必有失

索引要付出的代价:

消耗了更多的空间

虽然提高了查找的效率,但是新增 修改 删除的效率降低了

尽管如此,添加索引大部分情况下还是有意义的,毕竟查找是高频的操作,还是值得的

索引的基本操作

查看索引

show index from 表名;

创建索引

create index 索引名 on 表名(列名) ;

创建索引还是一个比较低效的操作,而且十分的危险

删除索引

drop index 索引名 on 表名;

删除索引的操作也是十分危险的

索引背后的数据结构(重点)

索引为什么查找的效率比较高/索引背后是什么数据结构?

首先回忆一下之前学过哪些数据结构

顺序表

链表

队列

优先级队列

二叉树 二叉搜索树

哈希表

ArrayList与LinkedList 有哪些区别?

首先,ArrayList的底层是顺序表,LinkedList的底层是链表

接下来就是一个==误区==:ArrayList查找比较快,LinkedList增加删除比较快,==这是错的==

首先ArrayList查找并不快,只是具备随机访问的能力

随机访问: 根据下标,获取元素

查找还是根据值来获取元素的位置,indexOf才是查找

ArrayList 查找的时候还是要根据下标进行遍历的,O(N) 并没有优势

LinkedList 增加和删除 也不快,在首尾进行增删还是可以的,O(1),在中间进行插入,还是要进行

遍历寻找节点,再进行插入

add(n,value); 还是通过下标进行描述的

所以从中间插入删除,之所以是O(N),并不是链表不行,而是linkedList方法的封装不太行

image-20220806200939578

哈希表和二叉树 二叉搜索树 都不适合作数据库的索引

哈希表虽然增删查改的很快O(1) ,但是它只能查询 值相等 的情况,无法处理< > between and 之类的比较大小的 范围查询

二叉搜索树的查询速度是O(N)[最坏情况] , 即使是红黑树 AVL树 (比较平衡的二叉搜索树)的查询速度也就只有O(logN)

要是数据库的数据很多,树的高度就会很高,查询的时间就会更长

所以,数据库的索引就有了一个专门的数据结构-- B+树(大部分的数据库都是B+树)

首先要知道什么是B树(也叫做是B-树, 注:这不是减号,而是连字符)

image-20220806203904778

B数是一个N叉搜索树,每个节点上最多包含N-1个值,B树的每个相邻的值是都是有范围的,这样子同样的元素的树的高度就会小很多,IO的次数就会减少很多,效率也会提高

但是索引的数据结构是B+树

image-20220806204842166

  1. B树的每个节点N个值,就会分出N+1个区间

    B+树N个值,会分成N个区间

  2. B树的值不会重复出现

    B+树的值会重复出现(父元素的值会在子元素中以最大值或者最小值出现)

  3. 到了叶子结点,B+树会将所有的叶子结点以链表的形式首尾相连,这样子十分利于范围查找

  4. 由于叶子节点是全集数据,所以只要将每一行的每一条记录关联到叶子节点上,非叶子节点只要保存 索引列,此时非叶子节点占用的空间很小,就可以在内存中缓存,查询的时候进一步减少了硬盘的IO

通过以上的讲解,面试题:谈谈索引是干啥的?

  1. 索引是干啥的?
  2. 索引付出的代价
  3. 索引背后的数据结构

事务(transaction)

原子性:一个事务的所有操作要么不间断地全部被执行,要么一个也没有执行。

举一个简单的例子,使用移动支付转账的时候,总体上要进行两步,将自己的钱减掉x,将对方的钱加上x,一旦,在我的钱减去x之后,银行的服务器挂了,对方的钱还没有进行操作,此时,就会很麻烦.

为了防止出现上面的情况,就希望按照原子的方式完成

要么全部执行完

要么全都不执行(要是执行一半是出现问题,能够自动恢复如初)

在事务的执行过程中,当执行过程中出现问题的时候,自动将前面的SQL效果还原 这就是回滚(rollback)

使用

  1. 开启事务: start transaction
  2. 执行多条SQL语句
  3. 回滚或者提交:rollback/commit

事务的开启,提交 回滚一般都是通过代码来实现的

事务的几大特性

原子性 : 事务的核心,能够将多条SQL打包成一个整体,要么执行完,要么就不执行,如果执行过程中出错,就进行回滚

一致性; 事务执行前后,数据处在"一致"的状态(数据能够对得上)

持久性:事务进行的改动,都是写到硬盘上的, 不会随着程序重启/主机重启而丢失

隔离性: (最复杂) 多个事务,并发执行的时候,事物之间能够保持"隔离",互不干扰

MySQL本质上就是一个服务器,执行SQL语句其实就是客户端将SQL发给服务器,让服务器去执行,事务也是发给服务器去执行

并发执行:同一时刻,多个客户端都想服务器发送了事务,让服务器去执行

如果这些并发执行的事务,操作的是不同的数据库/不同的表,就没事

要是这些操作的是相同的数据库,相同的表,就可能会出现冲突

隔离性存在的意义就是让并发执行事务的时候,尽量不出问题(问题控制在可控的范围内)

脏读: 一个事务A在修改数据,提交之前,正好被另一个事务B读取了数据,此时A就极有可能修改数据再提交 ,此时B事务独到的就是"无效的数据"也就是脏数据

如何解决脏读问题?

在提交之前,不能读,提交之后才能读(写完了才能读)

这就相当于是进行写加锁

没有对写操作加锁,写 和 读 是完全并发的 并发性最高,但是隔离性最低

对写操作加锁,并发性降低(效率降低),但是隔离性提高了(准确性提高了)

不可重复读:在一个事务A中,多次读取同一个数据,结果发现每次读到的数据不一样(也就是说读的时候被人改了)

不可重复读要通过读加锁 来 解决 (读的时候不能进行修改)

引入读加锁 ,进一步降低了并发性(效率降低) 但是 隔离性提高了(数据的准确性提高了)

幻读: 一个事务按照条件查询数据时,没有对应的数据行,但是在插入数据时,又发现这行数据已经存在,好像出现了"幻影"

要想解决幻读 问题 ,方法就是串行化

在进行了写加锁 读加锁 串行化 之后,并发程度已经降到了最低(效率最低),但是 隔离性最高(数据最精确)

上面说的脏读 不可重复读 幻读 都是在并发执行事务中 可能会带来的影响,这些影响不一定是bug,因为要看实际需求中要求数据的精确程度

衡量是不是bug的唯一标准就是符不符合需求

MySQL给我们提供了"隔离级别"选项 ,给了四个档位,根据实际需求,选择不同的档位

1.read uncommitted 允许读未提交的数据, 并发程度最高,隔离性最低,可能存在脏读/不可重复读/幻读 问题

2.read committed 只能读提交后的数据,相当于写加锁,并发程度降低,解决了脏读,可能存在不可重复读 幻读 问题

3.repeatable read 相当于读和写都加锁,并发程度再降低,隔离性在提高,解决了脏读 不可重复读 ,可能存在幻读问题

4,serializable 严格执行串行化,并发程度最低,隔离性最高,解决了脏读 不可重复读 幻读,数据最精确 ,但是效率较低

以上的设置都要在MySQL的配置文件 my.ini中设置 ,根据不同的寻求场景,就可以设置不同的档位

通过以上的讲解 , 面试题:

  1. 事务是干啥的?(从原子性切入)
  2. 事务有哪些特性
  3. 隔离性在并发事务中有哪些问题,以及如何解决(脏读 不可重复性 幻读)
  4. MySQL的隔离级别有哪些,和上面的问题有哪些对应
全部评论
那个二叉树画得非常好
点赞 回复 分享
发布于 2022-08-26 20:48 陕西
码住,多研读
点赞 回复 分享
发布于 2023-04-27 19:07 广东

相关推荐

2024-11-04 21:17
江南大学 Java
穷哥们想卷进大厂:肯定会问技术呀,面试你的可能是别人
点赞 评论 收藏
分享
戏子多秋m:项目做了有,但是没奖项,没实习,学校可能没有太大优势,建议项目写三个就可以了,技能点可能得优化下,个人感觉,我也是菜鸡,不是很懂,单纯个人建议,感觉秋招还在捞双非,加油兄弟
点赞 评论 收藏
分享
评论
2
11
分享
牛客网
牛客企业服务