mysql
2021-07-27 10:25:17 0 举报
AI智能生成
mysql学习
作者其他创作
大纲/内容
存储引擎
InnerDB
特点
支持事务
支持行级锁和外键
支持事务日志,可用来做数据修复
支持自增主键
没有记录数据行数,select(*)需要全表扫描
为了处理高性能的大量数据而设计
使用场景
读写同样重要
需要对事务的支持
索引的实现
主键索引是聚簇索引,主键索引B+树的叶子存数据
没有主键的话mysql会建一个隐式的主键用于构建索引树
非主键索引是非聚簇索引,叶子节点存主键,找到主键后回到主键索引树查找数据
推荐使用整形自增作为主键有利于构建索引树
日志系统
MYISAM
特点
不支持事务
不支持行级锁和事务
不支持自增主键
记录了数据条数,select(*)会直接拿出存的数据返回,不需要全表扫描
适用于大量读操作,更新操作会锁表,效率低下
使用场景
读多写少
不需要对事务的支持
索引的实现
三个文件:表名.frm存表结构数据,表名.MYD存储表数据,表名.MYI存储索引树
索引树中不存储数据,只存数据地址,二级索引也是一样,不用回表操作,通过定位到索引之后直接拿到数据地址去找数据
事务和锁
事务
事物的特性
原子性
事务是最小单位。不可再分
一致性
一个事物要么全部成功,要么全部失败
隔离性
多个事务之间相互隔离,互不影响
持久性
事务commit之后会被刷新到磁盘,不可逆
隔离性问题
脏读
A事务读到了B事务修改但是没有提交的数据,A做业务操作,此时B回滚,那么A拿的就是脏数据
虚读
A读了一批数据做业务,B来新增了一条数据,A再来读发现多了一条数据
不可重复读
A读了一条数据做业务,B来把这条数据修改了,A再来读发现数据变了
隔离级别解决隔离问题
读未提交
设置数据库隔离级别为读未提交,不能解决任何问题
读已提交
解决脏读,会出现虚读
mysql默认隔离级别
可重复度
解决虚读,会出现不可重复读
oracle默认隔离级别
串行化
解决不可重复度,执行效率低下,不推荐
数据库锁
乐观锁
cas理论实现乐观锁,每行记录维护一个version字段
悲观锁
行级锁
使用主键作为条件,会对查询出来的数据行加锁,只有当事务提交或者回滚才会释放锁,自动释放锁,会出现死锁
表锁
for update查询数据条数不确定,或者没有使用主键作为查询条件,会使用表锁,与上面的区别只在于锁的记录行数
间隙锁
当执行一条for update 不是数据库表索引时,会把该索引所落到的间隙锁住,已存在小于for uodate的最大值<间隙<已存在大于for uodate的最小值
库锁
通过Flush tables with read lock命令实现,数据库会变成只读状态,unlock tables命令解锁。
与数据库设置只读相比,这个命令会在客户端异常时自动释放锁,只读不会。不应该使用库锁做数据库备份,应该用mysql自带备份工具mysqldump做备份,在可重复读隔离级别下会自动开启一个事务保证导出数据的一致性
for update会被多个线程同时持有,导致死锁,当某一行数据不存在时,对其加for update锁,这个锁是会被多个线程同时持有,这时对这个数据更新时,都不能成功,死锁,第一个更新的线程会一直等待,第二个更新的线程执行检测到死锁会报错,此时第二个线程回滚,第一个线程就能更新成功
索引
分布式集群
日志系统
bin log二进制日志
概念
server层逻辑日志,记录的是每次数据库表的更新
bin log记录完成就认为事务提交完成
实现
STATMENT
记录sql语句,优点,占用空间小,缺点,如果有NOW()这样的内置函数的话会造成同步到其他机器的数据不一致问题,这是mysql默认的方式
ROW
完整记录sql执行后的数据变化,有点,不存在STATMENT中的问题,缺点,存储的数据量可能会比较大,去过出现表结构修改日志会暴增
MIXED
混合记录,遇到SATMENT的问题就用ROW记录,遇到表结构修改就用ROW记录
作用
一般用于数据库主从同步,slave通过读取主库binlog更新自己达到数据一致性的效果
其他
追加写入,比写磁盘快,当bin log写完成了,就认为执行完成,mysql会在空闲的时候将bin log修改同步到数据库中
可配置bin log文件大小,当一个文件写满了,会新建一个文件写。mysql默认不会删除bin log文件,可配置自动删除策略(删除周期),或者手动删除
redo log重做日志
概念
存储引擎InnerDB物理日志,记录表数据的更新,是环形区域,大小固定,不能无限写,只能记录一段时间的更新,环形写完了之前写的会擦除
一条更新sql执行之后记录,redo log记录完成就认为这条sql执行完成
实现
当一条更新语句执行,记录这条sql执行之后的结果到redo log,redo log记录完成就认为sql执行完成,环形区域顺序写,比磁盘随机写要快
作用
一般用于一段时间内诗句哭数据恢复,当一个
undo log回滚日志
概念
InnerDB实现的逻辑日志,记录了修改之前的数据,
实现
作用
general log一般查询日志
error log错误日志
slow query log慢查询日志
relay log中继日志
mvcc机制 (可重复读)
undolog示例: 1(id) 'chen'(name) 100(tx_id) 上一条的地址
前提:当事务开启,执行第一条更新语句时候,会向mysql申请事务id(tx_id),严格按照时间顺序生成,此tx_id会在记录undolog的时候同时记录
执行第一条查询语句,会生成针对该事务的一致性视图(read view),就相当于一个快照,read view在事务提交之前一直有效,read view是由当前时间所有未提交的事务id数组和已提交的最大事务id组成,例1,[100,150,200]300,例2,[100,150,200]80,例3,[100,150,200]180,根据read view,可将undolog(根据tx_id)分为三块,例1中min_id=100,max_id=300,例2中min_id=80,max_id=200,例3中_min_id=100,max_id=200
执行第一条查询语句,会生成针对该事务的一致性视图(read view),就相当于一个快照,read view在事务提交之前一直有效,read view是由当前时间所有未提交的事务id数组和已提交的最大事务id组成,例1,[100,150,200]300,例2,[100,150,200]80,例3,[100,150,200]180,根据read view,可将undolog(根据tx_id)分为三块,例1中min_id=100,max_id=300,例2中min_id=80,max_id=200,例3中_min_id=100,max_id=200
版本连比对规则
1,如果是当前事务id修改的,那么一定可见
2,如果tx_id<min_id,那么一定是已提交的事务,可见
3,如果tx_id>max_id,那么一定是之后生成的事务,不可见
4,如果min_id<=tx_id<=max_id,如果tx_id在read view的数组里面,不可见,反之,可见
查询语句如何拿到自己想要的数据?根据最后一条undolog依次向前找,根据上述规则,直到找到可见的数据,返回
关于读已提交,与上述规则一致,只是每次读的时候生成新的read view
sql执行过程
基本过程
客户端->server层->存储引擎层->数据文件
具体步骤
server层
连接器
检查权限等
缓存
查询缓存是否存在数据,如果已存在,直接返回给客户端,如果不存在,告诉连接器没有缓存
查询分析器
没有缓存情况下,会调用分析器,拆分sql语句,语法分析,此处会返回语法错误
查询优化器
优化索引查询,生成执行计划
执行器
与引擎层交互
存储引擎层
1,从磁盘将查询到的数据load到buffer pool,这里是根据数据页load的,所以查询一条数据,他附近的数据也会被load进去,mysql数据页大小为16kb
2,写undolog,将修改之前的数据记录在undolog中,方便以后回滚
3,更新buffer pool
4,写redolog buffer(redolog日志的一块buffer区)
5,提交事务,将redolog buffer写入redolog日志,此时redolog是准备状态
6,写binlog
7,binlog写完会通知redolog将状态改为commit状态,并且返回给客户端事务提交成功
8,buffer pool不定期将数据刷新到磁盘
细节详解
server实现了cache,但是这个cache很鸡肋,因为这里面的任意一条数据一旦被更新,整个cache就失效,所以在mysql8以后就移除了
buffer pool是不定期往数据文件写的,所以可能还没有更新到文件mysql宕机,这样数据一致性不能保证,再次重启,mysql会根据redolog恢复buffer pool,然后再往数据文件中写
提交事务成功的标志,二阶段提交完成,redolog变成commit,就认为事务提交成功,而不需要等到数据同步到磁盘,WAL机制(缓存定期写磁盘,比每次都直接往磁盘写要快,并且写磁盘不是顺序写入,效率低)
0 条评论
下一页