mysql基础问题
mysql 事务隔离级别
- 读未提交
- 读已提交
- 可重复度
- 串行化(每个读操作都加锁)
为什么要用可重复读
废话,我如果在一个事务中,两次查询的结果不一致,那我到底以哪个结果作为基准来执行我的程序
mysql知识进阶
什么是当前读
当前读,顾名思义 读当前最新的数据
比如说我们平时用到的 【update,delete,insert,for update,lock in share mode】都是当前读
读取的时候还会对当前的数据进行加锁,防止别的事务对当前数据进行修改。
(其实不光会对当前数据进行加锁处理,有时候还会将某个间隙进行加锁,也就是间隙锁,下面再讲)
什么是 快照读
快照,快照,这个名字多熟悉,故名思义,就是对某个时刻的某些数据的缓存。
mysql 中不加锁的select就是快照读 比如 select * from tab where name = '小二'
mysql中 快照读代表着 事务只能看到当前事务可以看到的数据,并不一定能看到最新的数据。
mysql 的快照读实现了 读已提交和可重复度两种模式
为什么要用快照读
因为他快啊 。
想比较与加锁的操作,快照读是 不加锁的非阻塞读,能够有效的提高并发性能。
不加锁====降低开销
快照读是怎么实现的
mysql实现了mvcc(多版本并发控制),在查询的时候会生成一个readview,
readview中包含当前活跃的事物和一些其他数据,mysql 会通过对比来查询出当前事务可以看到的数据。
简单来说是通过乐观锁的方式来实现的,因为 除了悲观锁 剩下的都是乐观锁实现
一句话概括就是这么简单
具体如何实现,下面再讲
mvcc的实现原理
MVCC原理 这个文章写的太好了,就没必要写了。
可重复度和读已提交在mvcc中的区别是什么
其实mvcc的实现原理已经看明白的话 这个问题很简单
两者的区别其实就是 readview的生成规则不一样
想想一下如果 readview是每一次查询的时候都生成一次,那不就是读已提交
间隙锁是干嘛的
想象这么一个场景:
#表结构:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`age` int(2) DEFAULT NULL,
`sex` int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `age` (`b`)
) ENGINE=InnoDB;
#数据
INSERT INTO `user` (`id`, `age`, `sex`) VALUES ('1', '18', '0');
INSERT INTO `user` (`id`, `age`, `sex`) VALUES ('1', '20', '0');
INSERT INTO `user` (`id`, `age`, `sex`) VALUES ('1', '22', '0');
INSERT INTO `user` (`id`, `age`, `sex`) VALUES ('1', '30', '0');
INSERT INTO `user` (`id`, `age`, `sex`) VALUES ('1', '31', '0');
INSERT INTO `user` (`id`, `age`, `sex`) VALUES ('1', '32', '0');
#索引树
在一个事务中(可重复读场景下)有以下两个sql
select * from user where age = 22 for update;(name有索引)
中间隔了5s
select * from user where age = 22 for update;(name有索引)
中所周知,mysql会锁定age = 22的数据
在只有行级锁的情况下能保证我第二次查询的时候也只有1条数据吗
答案是不能!!!
因为 我可能将其他数据的age修改为22
这样不就违背了 可重复读的初衷了
间隙锁就是来解决这个事情的
间隙锁会锁住name的索引树 小二的两侧的间隙(见下图)
这样别的update/insert/delete操作就无法进行,
这样就保证了 可重复读
mysql 优化
前述:mysql的优化建立在对索引结构B+树了解的前提下 自己找资料吧
什么是回表
了解回表就必须了解
聚集索引(主键索引)B+树叶子结点储存的是 行数据
非聚集索引(普通索引)B+树叶子结点存储的是 主键id
比如说 select b from tab where a = '123';(b 有索引)
那么这个查询就会设计到回表
查询过程:
第一步:
去b的索引树查找符合a=‘123’的数据,最终查找到,但是查到的是一个主键id
第二步:
拿着主键id去主键索引树 查询该id的数据
这就是回表,总共进行了两次索引树的查询
回表怎么处理
回表的解决办法就是 建立组合索引
建立 a和b的组合索引
这样在查询的时候在第一次搜索索引树的过程中也有b的信息,自然就不需要第二次查询了
范围查询必然会不走索引吗(between and,in 。。。)
不一定
如果范围较小 会走索引
范围较大,mysql分析器 分析出来该sql走索引的代价比全表代价还大,就直接不走索引了。
说说对最左前缀原则的理解
通过索引树就比较好理解了 组合索引 a和b和c的话在索引树中是这样的结构
在是先通过a来排序的,如果你先用b是无法来进行操作的。
什么是索引下推
索引下推index condition pushdown(ICP)
比如说一个sql
SELECT * from tab where a like '123%' and b=1
a和b是组合索引
根据最左匹配原则 遇到非等值判断时匹配会停止
那所以:
就只有 a可以用上索引
这样的索引查询步骤是:
第一步:
现在索引树查找到 like 123%的所有的数据的 主键id
第二部:
拿着主键id 去主键索引树查询相应数据
最后对比age
到此结束
but····························
上面的那个匹配原则其实都是5.5或者5.5之前版本的问题
5.6之后的版本没有这样的问题,就是通过索引下推解决的
有了索引下推之后就只查询一次索引树:
第一步:
现在索引树查找到 like 123%的数据 并对比 age的值
到此结束
|