MySQL 的索引事务
1. 索引
首先知道两个事情
- 索引 是一种 特殊的文件 ,包含对数据表所有记录的 指针 像目录
- 一个表是可以产生多个索引的
- 关键字是 index
索引的作用:
-
用于快速定位和检索
我们都知道 mySQL 每次的查询都会 遍历一遍这个列 利用好索引可以快速的 定位检索数据
-
数据库中 表 数据 索引之间的关系 类似于 书架中 图书 书中内容 目录 之间的作用
-
索引是一种 牺牲空间 提高时间的 一种 效率工具
1.1 使用
创建表时 创建主键约束 唯一约束 外键约束 都会自动创建 对应列的 索引
-
查看索引
show index from 表名;
-
创建索引
create index 索引名 on 表名(字段名);
创建班级表中 name字段的索引
create index idx_classes_name on classes(name);
创建索引的时候,需要针对现有数据,进行大规模的重新整理
所以创建索引操作也是一个 危险操作
创建索引 都是在创建表的时候规划好的,一旦表已经使用很久 有很多数据了 再修改索引 就要慎重了
-
删除索引
drop index 索引名 on 表名;
删除的时候 只能删除 手动创建的索引 不能删除 自动删除的索引
移花接木
如果真的有需要 修改索引 删除或者创建
我们可以先搞一个新的机器 创建空表 把旧机器的 数据导入到新机器 然后再新机器替换旧机器
1.2 索引的本质
数据库的索引 是一种 改进的 树形结构 B+树
首先大致了解一下 B 树 (N叉搜索树)
每个节点都有 m 个 key 划分出 m+1 个区间
进行查询的时候就可以直接从根结点出发 , 判定当前要查的数据 在节点上的 哪一个区间中 决定下一步往哪里走
进行添加/删除元素的时候 就涉及到了 结点的拆分和 节点的合并
B + 树 是 B 树的改进
也是一个 N 叉搜索树
-
每个节点都有 N 个 key 划分为 N 个 区间
-
每个节点上的最后一个 相当于 当前子树 的最大值
-
父节点上的每一个 key 都会以最大值的身份出现在相对应的区间子树中 (key 会重复出现) 也就意味着 叶子这一层包含了所有整个树 的数据集
-
B+树 用类似于链表的结构 将叶子节点串联起来
此时就可以很方便的完成数据集合的遍历
并且 按照所需范围 从数据集合中取出一个 子集
B + 树的优点:(相对于 B树)
-
N叉搜索树 书的高度优先 降低了 Io次数
-
非常擅长范围查询
-
所有查询最后都会落到叶子中 查询和查询之间的时间开销是稳定的
对于 B 树来说 要查询的元素 再 层次比较高的 节点 就很快 如果在比较下面的层次 就比较慢
-
行数据 存储到 叶子节点上 所以叶子节点会 非常占用空间
把 非叶子节点 缓存在 内存中 可以进一步减少 io的访问次数
2. 事务
事务可以把 多个 sql 打包成整体
可以保证这些 sql 要么全部都执行 要么就 “一个都不执行”
看起来是 “一个都不执行” 其实是 执行了 发现出错后 对数据进行了 回滚的 操作
可以理解成是 翻新
这样的特点 也称为 “原子性” 表示 不可拆分的情况
事务的特性:
-
原子性 :打包数据 可以通过回滚的方式 回到初状态
-
一致性 :让数据不会太离谱 通过数据库的约束 来完成
-
持久性 :事务所做出的修改 都是在硬盘中 持久保存的 重启服务器,数据依旧存在
-
隔离性 :
并发执行:多个客户端会让数据库执行事务 当客户端1 提交事务1 执行了一般 客户端2 提交的事务2 也来了
数据库这时 需要同时 处理 这两个事务
并发程度越高,整体效率就越高
但同时 也存在一定的问题 导致数据错误的情况
并发执行可能出现的问题:
-
脏读问题
一个事务A正在写数据的过程中,另一个事务读取了同一个数据
接下来 事务A 又修改了数据 导致 B 之前读到的数据 是一个 无效的数据/过时的数据
(如果一个一个执行 就不会出现问题)
解决脏读问题:针对 写操作 进行加锁 ,让 写操作 写完以后 再读 ,并发程度降低
-
不可重复读
并发执行的过程中,如果事务A在内部多次读取同一个数据的时候,出现了不同的情况 原因是:事务A在两次读之间 有一个 事务B 修改了数据并提交了事务,这就是 不可重复读。
解决不可重复读问题:针对 读操作 进行枷锁,让 读的过程中不能写
并发程度有进一步降低了,隔离性也进一步提高了,效率降低了,数据准性又提高了
-
幻读(是不是问题 要具体场景具体分析)
在 锁了 写操作和 读操作 之后 一个事务A执行的过程中 ,两次读取操作,数据内容没变但是 结果集变了(可以理解成 多了一份不同的数据集)
解决:映入串行化的方式 ,保持一个绝对的串行执行事务,此时完全没有并发了,效率是最低的 数据是最准确的 同时 隔离性是最高的
-
2.1 使用
-
开始 事务
start transaction;
开启事务后 后面所写的 sql 都会被打包 拥有“原子性”
-
执行多条 sql 语句
-
回滚/提交 : rollback/commit
这里是 主动出发回滚 一般要搭配一些 条件判断逻辑来使用的
回滚 是怎么做到的?
日志的方式 ,记录事务中的关键操作,这样的纪律就是回滚的依据
3. 隔离级别
效率 正确性 ====> 不同的需求场景就有不同的需求
比如 转账 支付 这一些列和钱相关的场景 宁愿牺牲效率 也要保证正确性
短视频 转发 点赞 这些 数量要求不高 就可以 牺牲正确性来 增加效率
mySQL 服务器也提供了“隔离级别“让我们针对隔离成都进行设置
-- 并发程度最高,速度最快,隔离性最低,准确性最低
read uncommitted;-- 读未提交
-- 引入写枷锁 只能读写完之后的版本 解决脏读问题
-- 并发程度降低,速度降低,隔离性提高,准确性也提高
read committed; -- 读已提交
-- 引入读枷锁以及写枷锁 写的时候不可读 读的时候不可写 解决不可重复读问题
-- 并发程度进一步降低,速度降低,隔离性提高,准确性也提高
repeatable read; -- 可重复读
-- 严格按照 串行 的方式进行 一个一个的执行事务
-- 没有并发,速度最低,隔离性最高,准确性也最高
serializable; -- 串行化
标签:事务,并发,--,索引,MySQL,数据,节点
From: https://www.cnblogs.com/ljy2003/p/18461880