本笔记通过看 B站IT老哥获得
文章目录
MVCC
多版本并发控制multi-version concurrency control 主要是为了提高数据库的并发性能
提高读写性能
什么是innodb的当前读和快照读?
当前读:
读取数据库记录 都是当前最新的版本会对当前读取的数据进行加锁 防止其他事物修改数据 是一种悲观锁操作
select lock in share mode(共享锁)
select for update
update(拍他锁)
insert(排他锁)
delete(排他锁)
串行事务隔离级别
快照读
快照读的实现是基于多版本并发控制的 mvcc 既然是多版本
那么快照读 读到的数据不一定是当前最新的数据
有可能是之前历史版本的数据
其中读已提交和可重复读是mvcc实现的
不加锁的select 操作 事务级别不是串行化
补充:
原子性是通过:undo log实现
持久性是通过 redo log实现
隔离性 就是通过加锁来实现 mvcc去实现
四种隔离级别
第一种 读未提交
第二种 读已提交
第三种 可重复读
第四种 串型化
mvcc概念
第一个是undo log
版本链是undo log 和 回滚指针
mysql百万级别数据优化
平均查询 4.3ms
不加索引 无缓存
select SQL_NO_CHCHE *from test_user where phone=‘1342414134’ and lan_id = 121 and region_id = 53;
优化开始
1、加索引 0.009ms
ALTER TABLE test_user ADD INDEX idx_phone_lan_region(phone,lan_id,region_id);
2、最左前缀法则
如果建立的事复合索引 索引的顺序要按照建立时的顺序,即从左到右 a->b->c (和B+树的结构相关)
第一个索引是 phone
第二个索引是 lan_id
第三个索引是 region_id
用explain查看索引的使用情况
EXPLAIN SELECT * from test_user where phone=‘1412141134’ and lan_id=121 and regin_id=53;
级别是 ref 级别
去掉中间的 索引 lan_id 索引字段变小 查询行数变大(一座桥 去掉桥中间 只能走到桥头)
EXPLAIN SELECT * from test_user where phone=‘1412141134’ and regin_id=53;
去掉头部索引 (一座桥去掉桥头 到不了桥中间和桥尾)
EXPLAIN SELECT * from test_user where phone='1412141134 and regin_id=53;
type 是全部 级别不好
ref 是null
行数 是差不多百万级别的行数
3、不要对索引做以下处理
计算 +、 -、 *、 /、 !=、<>、is null 、is not null、or
函数 sum() 、rand()
手动/自动类型转换 id =”1“; 本就是数字给转换成字符串
4、索引字段不要放在范围查找的右边
索引字段如果放在范围查找的右边 将使用不到 索引会失效
EXPLAIN SELECT * from test_user where phone=‘1412141134’ and lan_id>121 and regin_id=53;
像本条语句 regin_id使用不到 索引字段长度 依旧是原来的数字
5、减少select * 的使用 ,使用覆盖索引
select 查询语句和where 中使用的索引字段一致
就是我查询 a、b两个字段 索引字段正好也是 a、b
如果 不采用这个 会浪费好多性能 还有带宽
6、like模糊搜索
失效情况 like “%张三%”
“%张三”
解决方案 使用复合索引
使用复合索引 即like 字段是 select的查询字段 如 select name from table where name like “%张三%”
使用like “张三%”
eg:EXPLAIN SELECT * from test_user where phone=’%1412141134%“;
级别是all 级别 用不到索引 所以索引失效 sql 性能弱
像这个去掉% 就ok了
EXPLAIN SELECT * from test_user where phone='1412141134%“;
建议使用最右边的百分号
使用一下覆盖索引试用一下
EXPLAIN SELECT phone from test_user where phone='1412141134“;
这条语句 特别影响性能
EXPLAIN SELECT * from test_user order by create_time asc
mysql锁
行锁
首先mysql 使用的是自动提交事物 所以验证锁的时候要先把这个事务提交去掉
变成手动提交事物 set autocommit = 0;
当我在一个窗口里修改我的一条语句锁的时候
手动提交开启 我们行锁是对内容进行操作 update 更新语句 内容在总数据库不会发生变化,内容但是在本窗口查询已经改变
避免了脏读
只有手动提交事务之后才会全局会更改
其他数据是无法看到我的操作的
因为数据进行了保护所以不会发生幻读的发生
如果想全部更新 就 使用 >commit 语句
如果两个回话 同时对一行数据进行更改
第一个回话没有修改完数据 提交完 其他数据是无法进行更改的 只能发生阻塞操作
表锁
产生原因 索引失效 主要用了or
update test_innodb_lock set b=‘a4’ where a=1 or a=2;
commit
主要是行级锁 索引失效 就升级成为 表级锁
只有当表级锁使用完
对其他表进行更改的语句才会生效 否则进行阻塞
间隙锁
间隙锁 一看就是在范围查询里面
eg:比如查询 1-9的数据 就会对1-9 进行加锁 如果要插入
一个回话:update test_innodb_lock set b= ‘4’ where a>1 and a<9;
第二个回话:insert into test_innodb_lock values (4,“b6”);
其中第一个进行更改的时候 第二个插入不进去
show status like “innodb_row_lock%”