欢迎关注个人主页:逸狼
创造不易,可以点点赞吗~
如有错误,欢迎指出~
目录
mysql索引
代价
查看索引
创建索引
删除索引
索引背后的数据结构
B树
B+树
B+树与B树的区别
B+树的优势
mysql事务
事务 涉及的四个核心特性:
隔离性详细解释
脏读
不可重复读
幻读
隔离性的四个级别
read uncommitted 读未提交
read committed 读已提交
repeatable read 可重复读
serializable 串行化
mysql索引
索引 类似于书的 目录,引入 索引 是为了 提高查询的速度
select这样的操作,默认是按照"遍历"的方式来查询,即时间复杂度为O(n),但这里的 读的是硬盘,而在数据结构里的O(n) ,遍历的是内存
代价
- 引入索引 需要消耗额外的 存储空间
- 引入索引后,确实能提高 查询的效率 ,但可能会影响 增删改的 效率(有时会 更快,有时会更慢,也或者 没变化)
比如: 通过条件判断 的方式来 删除 delete from student where id = 5; 其中where id=5 背后就有查询操作
索引有利有弊,实际开发中 还是推荐使用 索引
- 硬盘往往不是主要矛盾
- 对于增删改查 也不一定都是 负面影响,也可能会 触发一些正面效果
- 很多业务场景 查询的 频率 要比 增删改 要高很多
查看索引
show index from 表名;
主键自带索引
unique 和 foreign key 也自带索引
创建索引
create index 索引名 on 表名(列名);
创建索引 其实是一个危险操作,针对 空表 或者 表中只有 较少数据(几千,几万...)创建索引 谈不上危险 但是一旦数据量 比较大( 千万级别),此时创建索引操作 可能会触发 大量的硬盘IO,直接把机器卡死了, 所以在 最初建表时 要哪些索引要提前规划好,创建好
删除索引
drop index 索引名 on 表名;
只能删除 自己创建的索引,不能删除自动生成的 ,删索引也是 危险操作.
索引背后的数据结构
所谓"构建索引" 其实是 引入一些数据结构 对数据进行存储,从而 提高查找速度~
二叉搜索树 和 哈希表 的查找效率都很高,但是都不适合 给数据库做索引
原因:
- 二叉搜索树 最大的问题在于 "二叉",当要保存的 元素多的时候,会使整个树的 高度变高(高度变高,比较的次数就会变多,伤硬盘~)
- 哈希表 最大的问题在于 只能进行"相等" 查询,无法进行 < >这样的'范围查询',也无法进行 like 模糊查询(哈希表 是通过哈希函数 把查询的key 映射成 数组下标)
B树
也写做 B-树(这里的 - 是连接符)
B树 是N叉搜索树(每个节点 ,可以有 多个子树,树的度是 N, 这样降低了树的高度)
每个节点不是 存储一个key值,而是会存多个 ,某个节点保存了 N个key,就能延伸出 N+1个子树,
和某个节点比较的时候,先一次硬盘IO,把所有的这个节点的内容都读出来,再在内存中比较,这里最主要的目的: 不是为了减少 比较的次数 而是要减少 硬盘IO的次数
B+树
B+树 ,为数据库 量身定做的数据结构 ,针对B树做的进一步改进的数据结构,B+树也是N叉搜索树
上图中的15是该B+树的最大值
若要进行 范围查询id>4 and id<10 ,从4开始,沿着链表往后遍历到10即可完成查询~
B+树与B树的区别
- B树 是有N个key,划分成N+1个区间 ,B+树 是有N 个key,划分出N个区间
- 父节点中的key值 会在下面的子节点中再次出现 (成为子节点最大值)
- B+树把叶子节点 像一个链表一样 连在一起了(此时进行 '范围查询' 就非常方便了)
B+树的优势
- N叉搜索树,树的高度比较低,此时硬盘IO次数就比较少
- 叶子节点是全集, 并且用链表结构连接,非常便于范围查询
- B+树 所有查询都要落在叶子节点上完成的 ,任何一次查询,经历的IO次数和比较次数 都是差不多的,查询的开销稳定(稳定意味着 成本容易被预估出来)
- B+树的叶子节点是全集,所以 非叶子节点上不必存储 "数据行"(比如:数据行: "1 ,张三, 男, 100分),只需要存储索引列的 key即可(非叶子节点占据的空间小,可以直接加载到内存中,进一步减少了硬盘IO的访问次数)
mysql事务
事务 是用来解决一类 特殊场景的问题(有些场景,完成某个操作,需要多个sql 配合完成,例如 转账)
事务 是把多个执行的SQL 打包成一个'整体',这个整体 在执行的过程中要做到 要么整个执行完,要么一个都不执行 (这里的"一个都不执行"实际上是"回滚"机制),避免出现 类似于" 转账转一半" 的情况.
回滚 :当sql执行到一半发现出错了 ,数据库会自动进行"还原操作"(相当于把前面执行过的sql给 '撤销'了,最终效果就像 一个sql都没有执行的效果). 回滚操作 只是针对 事务 来说,不能将想 "drop database "这样的操作 回滚回来
事务 涉及的四个核心特性:
- 原子性(最重要的特性),上面提到的 '整体'即原子性.
- 一致性 ,事务执行的前后数据库中的数据都是'合法状态',不会出现 非法的临时结果的状态
- 持久性.事务执行完毕后,就会修改 硬盘上的数据,事务都是会持久生效的.
- 隔离性, 描述了 多个事务 并发执行的时候 相互之间产生的影响是怎样的
隔离性详细解释
并发执行: mysql是一个 '客户端- 服务器'结构的程序, 一个服务器通常会给多个客户端 同时提供服务,因此 很可能,多个客户端会同时向 这个服务器提交事务来执行,服务器就要同时执行这些多个事务,此时就是 并发执行.
若此时 同时执行的事务 恰好是针对同一个表 进行 增删改查 ,此时就可能会引入 一些问题:
脏读 ,不可重复读 , 幻读.
脏读
指一个事务读取的数据是 "脏数据"(过时的数据)
举例: 有两个事务A和B 并发执行,
其中 事务A 是针对某个表的数据 进行修改 .A执行过程中,B也去读取这个表的数据, 当B读完后,A把表中的数据又改成了别的,
这样就会导致B读到的数据 不是最终的"正确数据" ,而是临时性的 "脏数据"
解决方法: 给写操作加锁(即在修改的时候,不能读)
不可重复读
指的是 一个事务里 多次读取的结果不一样
举例: 有三个事务ABC ,
事务A执行完一个修改操作,提交数据,事务B再执行,读取刚才A提交的数据,
在B读取的过程中,事务C又对刚才A修改的数据 再次做出了修改
对B来说,后续读到的这个数据 和第一次读到的是不一样的.
解决方法: 给读操作加锁(一个事务在读取数据的过程中,其他事务不能修改它正在读的数据)
幻读
幻读 是不可重复读的特殊情况
举例"事务A在读取数据时 ,事务B 新增 或 删除了一些数据
A多次读取的数据虽然 一样,但是 '结果集'不同
解决方法:'串行化'(只要是 读的时候,就不要有任何操作.)
隔离性的四个级别
针对上面3个问题, mysql 提供了四个隔离级别,可以通过 配置文件来设置当前服务器的隔离级别
设置不同的隔离级别 会使事务间的并发执行产生的影响有差别
read uncommitted 读未提交
一个事务可以读取 另一个事务未提交的数据,此时就可能会产生 脏读.不可重复读,幻读 三个问题
但是此时,多个事务并发执行的程度是 最高的,执行速度也最快.
read committed 读已提交
一个事务只能读取另一个事务提交之后的数据(给写操作加锁),此时会产生 不可重复读 和 幻读 两个问题(脏读问题解决了),此时并发程度会降低,执行速度会变慢,但是事务之间的隔离性提高了(事物之间影响变小了,得到的数据更准确了)
repeatable read 可重复读
相当于给读操作和写操作都加锁了.此时可能会产生 幻读问题(解决了脏读和不可重复读问题),
并发程度进一步降低,执行速度进一步变慢, 事务的隔离性进一步提高了.
serializable 串行化
所有事务都是在服务器上一个接一个的执行的,此时解决了脏读,不可重复读,幻读问题
并发程度最低,执行速度最慢,隔离性最高,数据最准确