目录
等待时间长(大概率是锁表,或锁冲突导致的),让查询一直处于等待的状态
联合索引的设计策略1.高频的查询条件 将最频繁出现在where,join,order by中的列放到左侧
日志类型,日志信息
错误日志:mysqlId在启动,运行或者停止时候遇到的问题(启动失败,运行崩溃)
一般查询日志(General query log):已建立的客户端连接和从客户端收到的语句
慢查询日志(slow query log):执行时间超过long_query_time指定秒数的查询(优化的场景)
二进制日志(Binary log):更改数据的语句(用于主从复制)
中继日志(Relay log):从源服务器接收到的数据更改(来源于集群中的主服务,比如我们抄学霸的作业,我们可以拍照,然后再抄,节省时间)
DDL日志:DDL语句执行的操作
回滚日志(undo log):用于事务的回滚操作
重做日志:用于服务器崩溃恢复
默认情况下,除windows上的错误日志外,不启用任何日志,Linux下默认开错误日志和二进制日志
在服务器运行期间可以控制一般查询和慢查询日志的禁用和开启,也可以更改日志名
一般查询日志和慢查询日志记录可以写入日志表,日志文件或者两者同时写入
默认情况下,所有启用的日志将写入数据目录,可以通过刷新日志强制服务器关闭并重新打开日志文件
通过FLUSH LOGS语句刷新日志来强制服务器关闭,并且重新打开日志文件,也可以使用mysqladmin的flush-logs或者refresh参数,或者mysqldump的--flush-logs或者--master-data
中继日志仅用于主从复制过程中的从服务器。
一般查询日志和慢查询日志的输出形式
如果启用一般查询日志和慢查询日志,日志的输出方式可以指定为日志文件或者mysql系统中的general_log和slow_log表,也可以两者同时锁定
启动时日志控制
log_output系统变量指定日志输出的形式,但是并不会真正启用日志,log_output可以有三个值,分别是:table(表),FILE(文件),NONE(不输出),可以同时指定多个值,并且用逗号隔开,未指定值时默认是FILE,如果列表中存在NONE则其他的不生效,也就是说NONE的优先级更高
可以通过general_log系统变量的值来控制一般查询日志的开启1与禁用0,如果日志指定自定义的路径和文件名可以使用general_log_file系统变量(绝对路径)
通过设置slow_query_log系统变量的值来控制慢查询日志的开启1和禁用0,如果要为日志自定义的路径或者文件名就可以使用slow_query_log_file系统变量
mysqldumpslow-总结慢查询日志文件
当某些查询语句执行时间过长,执行时间超过设定的阈值时,我们称这个查询为慢查询
慢查询相关信息用日志记录下来称为慢查询日志,mysqldumpslow可以解析慢查询日志并且汇总其内容:mysqladmin status -uroot -plcl15604007179
当前服务器内容少,暂时没有慢查询,
比如select *from student where id=1
select *from student where id=10 此时这个id会被记录称
select*from student where id=N
通常情况下,mysqldumpslow会将查询分组并显示摘要输出,一般会把数字和字符串用N和S代替。
count执行的次数
Time单次的耗时
Lock申请与释放锁所用的时间
Rows获取数据所用的时间
mysqldumpslow
Mysqlbinlog处理二进制文件
对数据库的增删改,都会被描述成一个事件,每个事件以二进制文件录在一个文件里面
称为Binary Log
mysqlbinlog 能够以文本格式,显示二进制日志文件的内容
mysqlbinlog binlog.00001
at xxx 一个事件在日志文件中其实偏移位置
end_log_pos 事件在日志中结束的偏移位置
慢查询sql优化思路
SQL执行时间长的原因
等待时间长(大概率是锁表,或锁冲突导致的),让查询一直处于等待的状态
执行的时间长:
- 查询sql写的烂
- 索引失效
- 关联join太多
- 服务器调优及各个参数设置
慢查询优化思路:
- 优先选择优化,高并发执行的SQL,因为高并发执行的SQL带来的后果,更加严重
比如下面两种情况:
- SQL1:每小时执行1w次,每次20个IO,优化之后每次18个IO,每小时节省2万次IO
- SQL2:每小时10次,每次2w个IO,优化之后,每次减少2k个IO,每小时省2w次IO
SQL1vsSQL2
- 高并发通常指单位时间内执行次数多(如 QPS 高),而不是单次资源消耗高。
- SQL1 的执行频率(每小时 10,000 次)远高于 SQL2(每小时 10 次),因此:
- SQL1 是高并发查询。
- SQL2 是低频但高资源消耗的查询
定位优化对象的性能瓶颈
- IO:数据访问的时候,消耗太多的时间,查看是否使用了正确的索引
- CPU:数据运算花费了太多的时间,数据运算的分组,排序是否存在问题。
- 网络带宽:如果网络带宽受限,数据传输的速度也将受到限制,从而导致查询的响应时间增加了
明确优化的目标:明确数据库当前的状态,数据库与当前该条SQL的关系。
当前SQL的具体的功能:尽量选择优化那些对业务影响比较大的SQL。
从explain执行计划入手
只有explain能告诉你当前SQL的状态
永远使用小表(小的结果集)驱动大表(大的结果集) 比如
for(int i=0;i<5;i++){
for(int j=0;j<1000;j++){
如果小的循环在外层,对于数据库连接,只需要连接5次,进行5k次操作,否则我就连接1000次每次5次操作。
尽可能在索引中完成排序:
因为索引本身是排好序的,排序字段在索引中的话,速度是比较快的
只获取自己需要的列
不用select *
只去使用最有效的过滤条件:
误区:where后面的条件越多越好,实际上是用最短的路径访问到数据才是最好的,即选择最有效的,比如用id就可以确定
尽量避免复杂的join和子查询
每条sql的join操作,建议不超过3张表
将复杂sql拆分成多个小sql,单个表执行,获取到结果区程序中封装就好
合理设计并且利用索引
1.较为频繁的作为查询条件的字段,应该创建索引
2.唯一性太差的字段不适合单独的去创建索引。比如性别 状态 状态字段,当一条query所返回的数据超过了全表的15%的时候,不需要使用索引扫描了
3.更新频繁的字段,不适合创建索引,因为索引字段被更新,还要维护索引文件
4.不会出现在where条件中的字段,不需要创建索引
如何选择合适的索引?
1.对于单键索引,尽量选择针对当前查询效果更好的索引
2.选择联合索引时候,当前查询中过滤性最好的字段,应该放到索引的最左侧
explain
type列:
如果对主键或者UNIQUE唯一索引的等值查询,type的类型就为const,最多只返回1行数据,速度非常快,const基础上表里只有一条数据(system,但是不在innodb引擎里面,一般在MySAM引擎是可以出现的),接下来看一下eq_ref,ref,ref_or_null,
eq_ref通常发生在联表查询中,关联的条件某一张表的主键或者UNIQUE唯一非空索引
性能,仅次于const
ref最常见,当满足索引的最左原则,同时并不走主键或者UNIQUE唯一非空索引,则为REF
对于非聚簇索引的单值查询,一般都为ref,
ref_or_null和ref大差不差,在上面的基础上,增加null值的查询,则为ref_or_null。
由于查询null值需要扫描整个索引树的行信息,所以比ref慢。
index_merge:将多个搜索结果合并成一个,还可以对结果排序,从而降低查询代价
永远去用小的结果集驱动大的结果集,目的就是减少内层表读取的次数
range:between,like,in,大于,小于,都是range,由于要对索引树扫描,效率并不高
index和all:两种都是全表扫描,区别index只需要查询索引树就可以拿到结果,all还需要遍历所有行,两种效率都低
Extra列
using index就是覆盖索引,也就是想要查找的数据都在索引树中,不需要回表再去查询聚簇索引,这样就可以减少不必要的查询,从而提升查询效率
using index condition 索引下推,index Condition Pushdown,即ICP,(5.6后的优化手段)假如搜索时候,需要大量回表,在回表之前,会先把处理过滤逻辑,下推到存储引擎汇总进行。过滤整理后,发到Server层进行处理,这样就减少了发给Server层的数据量和次数,提升了效率
using where和using index相对,所有的过滤动作都由Server层处理,效率会比较低,从分析可以看出,假如但看效率低话,using index>using index condition>using where(记得去优化)
using MRR:对二级索引查询时候,会优先对二级索引的查询结果缓存并进行排序,然后统一去聚簇索引中回表查询,这样可以把随机IO优化成顺序IO,提升效率,需要关闭mrr_cost_based才能确保使用mrr.
using join buffer(BNL,BKA)
A,B两表关联查询,A的关联列上有索引,而B的没有,就会发生BNL优化,从A表去失调数据,放到Join Buffer中,再去全表扫描B表和Join 和Buffer这10行进行关联,循环这一步,直到A表的所有数据都关联完为止。虽说这是优化,减少B表的扫描次数,但是还是慢,规避
BKA ,在BNL的基础上,B表如果有索引,配合MRR,将JoinBuffer中的行进行排序之后去B表对应索引中查询,而无序全表扫描 默认关闭
using union,如果多个查询条件都是索引,那么会对索引进行合并,会出现using union,一般伴随着typeindex_merge.
using temporary:使用到了临时表,比如group by,distinct ,union等语句时候,可能用到临时表
using filesort:在查询之后,进行一些排序,在查询之后,需要单独进行一次排序,会出现using filesort,当然我们可以进行一些优化,不需要这次额外排序,只需要将条件和排序两个字段组成联合索引即可。这样定位到条件之后,由于联合索引,排序字段本身有序,不需要额外排序了。
联合索引的最左匹配原则
最左匹配原则是对联合索引的一个查询优化,既定的一个规则
联合索引式由两个及以上的字段组成的索引,就叫做联合索引,生效条件是必须从最左侧(A)开始且开始连续使用索引列
本质原因:索引的B+树按联合索引顺序排序(先按A排序,A相同再按照B排序)
依据第一个,第二个字段,按顺序的匹配,才能用联合索引
比如联合索引(A,B,C)
where A=1 使用最左列A,触发索引
where A=1 AND B=2 连续使用A和B
where A=1 and B=2 and C=3 全列匹配,效率最高
where A=1 and C=3 仅A生效,C无法使用索引(中间缺少B)
where B=2 and C=3 不生效,未从最左列A开始,全表扫描
where A>1 and B=2 部分生效 ,仅A生效,范围查询后无法使用B(B需要再内存中过滤)
(name,city,age)
varchar(50)如何计算 -4*50加2个变长(null)
联合索引的设计策略
1.高频的查询条件 将最频繁出现在where,join,order by中的列放到左侧高频查询 : where name='张三' and age=15
最优索引(name,age)
2.列区分度:
区分度高的列(唯一值多)放到左侧,快速过滤更多数据
区分度=count(Distinct colum/count(*) (值越大,区分度越高) sex :男女,性别区分度,2/100就是
name有200个值,gender有两个值,优先吧name放到左侧(name:gender)
3.排序与分组需求
假如查询Order by或者Group by 将排序列假如索引,并且保持一致
where name='张三' order by age desc
最优索引:(name,age)
4.覆盖索引优化
若查询字段均包含在索引中,可以避免回表(Extra列显示using index)
select name,city,name from user where name='张三';
覆盖索引:(name,city,age)
设计覆盖索引案列(最左匹配)
查询1:where name='张三' and city ='北京' order by age desc
查询2:where country='中国' and name='张三'
索引设计:
方案1:(name,city,age) 优化查询1,覆盖索引
方案2:(name,country)优化查询2
根据查询频率决定优先级更高的索引。
误区
低区分度的放到最左 过滤效率低 按区分度从高到低排列
忽略排序/分组字段 导致filesort临时表(性能下降) 将排序列加入索引保持顺序一致
过度追求覆盖索引 索引字段过多,写入性能下降 包含高频查询字段
思考一下
索引(name,city,age)是否可以优化where city='北京' and name='张三‘
可以,优化器会优化把顺序自动调整为name='张三' and city='北京
MVCC
多版本数据,每个修改操作生成数据行的信版本,旧版本通过Undo Log保留
隐藏字段:每行数据包含两个隐藏字段:
DB_TRX_ID :最后一次修改该行事务的id,6字节
DB_ROLL_PTR:指向旧版本数据的指针(Undo Log地址)
ReadView读视图
m_ids:生成ReadView时活跃且未提交的事务ID列表(除当前事务之外的其他事务ID列表)
min_trx_id:活跃事务中的最小ID
max_trx_id:生成ReadView时下一个待分配的事务ID 生成ReadView的最大的ID+1即可
creator_trx_id:当前事务的ID
MVCC是啥,解决什么问题,什么
每个事务修改一次,就要去生成一个新的版本,不同的事物去读不同的版本
在不可重复读的隔离级别下,让事物每次读到同一个版本的数据,这样每次读到的都一样了,就能避免可重复读的问题。
所以把修改的数据版本记录到一个undo log日志中,给表增加一个隐藏字段回滚指针,回滚指针指向这个undo log日志 (一个事务来查找数据,我怎么知道哪个版本的数据)
说明生成版本事务的数据还没提交,没提交的肯定不能让当前事务看见,
相反,如果这个数据版本的trx_id不在m_ids列表中,说明啥?说明生成数据版本的事务已经提交了,已经提交了就肯定能看了,所以这个数据版本对当前事务是可见的
但是trx_id小于min_trx_id就说明肯定是小于的,能看到
trx_id大于max_trx_id没启动呢还,就不用管了
每次修改数据,就记录修改的事务id到隐藏字段,然后生成一个版本,去记录到这个redo log的版本链当中,然后回滚指针指向版本链,通过对比redo_log
一个事务第一次读取之后,后面每次读取的数据都应该和第一次一样,维护一个数据多个版本,事务修改一次,就生成一个版本,不同事物读不同版本,读已提交的情况下,让事务去读已经提交的数据版本,这样就避免脏读了,
不可重复读的隔离界别下,让事务每次读到同一个版本的数据,这样每次读到的都一样了,避免了可重复读的问题,因此,把修改的数据版本,记录到一个undo log日志中,给表增加一个隐藏字段叫回滚指针,回滚指针指向undo log日志,使用回滚指针把历史版本连接成一个链表,这样想读哪个版本,沿着链表一直找就好,一个事务来查数据,怎么知道我要去查哪个版本的数据,所以要给每个事务分配一个事务id,事务id自增分配,通过对比事务id大小,就能知道哪个事务创建的比较早,哪个事务创建的比较晚(然后再去记录哪些事务提交了),哪些事务没有提交,然后让提交的比较早的事务,不要看到提交比较晚的就好
给表增加一个隐藏字段
修改数据的事务id(trx_id):谁修改了他,就把对应事务id记录下来,
还需要read view(四个重要字段)
creator_trx_id:创建当前readview的事务id
m_ids:创建readview时,当前数据库中活跃且未提交的所有事务id
min_trx_id:创建readview时,数据库活跃且未提交的最小事务id
max_trx_id:创建readview时,应该分配给下一个新建事务的id
undo_log去记录数据版本,RedaView去判断数据版本对当前事务的可见性(MVCC)
如何实现各个隔离界别呢?
串行化:加锁
可重复读:第一次select的时候生成一个read view(用来判断数据版本对当前事务的可见性的)
可重复读每次都会复用第一次生成的review,也就是说当生成这个read view的时候,哪些版本对当前事务可见已经固定了,后续通过同一个readview去判断数据的可见性,因此,每次读都是同一批数据版本
可重复读通过复用readview加MVCC机制(为了
读未提交:每次select都会生成一个新的readview,每次读都生成了新的readview,每次读都能读到新提交的版本了,
幻读:可重复读如何尽量解决(分两种情况,1.快照读,在可重复读的隔离级别下,当执行普通的select语句时候会生成一个快照,通过MVCC去读,每次都读同一个数据版本,这就是快照读,普通select通过快照读去避免加锁,每次都去读快照,别的事务不去关心,读不到就不会幻读(但是不能永远读不到吧),比如你先开启了事务,别人后开启了事务,但是别人先插入id为1的数据
,但是你读不到,会以为id为1读数据不存在,那就去插入id为1的数据,但是不能插入啊,
插入这种操作比如读到新的数据,才能判断是否插入,这就是当前读, select for update或者select in share mode或者执行(增删改 insert update ,delete都是当前读)的操作,当前读读的都是最新的数据,如果其他事务插入了,那不就还会产生幻读吗,执行当前读,mysql会使用临键锁,锁住数据和数据直接的间隙,我加锁了,你就不可以插入,只要我不让你插入修改啥的就好,
for update 当前读,加临键锁 (不让你插入,不就没有幻读了吗)(可以解决大部分问题)
下面一直阻塞,就报错误了,但是就是不能查,直到我去提交事务,
可重复读的隔离级别下,通过MVCC快照读,加上当前读加锁的方式避免幻读的,有极端情况,先快照读再当前读(如何解决)
比如这种(轻微诡异)
事务A(第一次查表里面没有,B提交之后,A查还是没有,但是当前读能查到)
事务B
(重度诡异) A查找没有,B插入,A插入发现冲突了,存在,A在查找,还是没有
![]()
A但是能直接修改,改完去查就可以查到
(以上这种这么解决)一个事务操作某张表,另一个表不允许新增啥的,可以select for update加表锁,事务b插入数据就会阻塞(不让你插入就不会有幻读)
比如 where有索引列,就会加行锁,比如select 字段from 表 where id>=5 and id<=10 for update,这样就会使用临键锁,锁住5和10这两条记录,还会锁住5-10之间的间隙,即6,7,8,9都不能插入
分库分表
索引失效场景
对索引使用左或者左右模糊匹配
对索引使用函数
对索引进行表达式计算
对索引隐式类型转换
联合索引非最左匹配
Orderby和groupby 会用到联合索引吗
like如何避免全表查询
假如使用的是固定前缀 start% 这种情况,就可以通过索引,查找前缀,然后使用%
Mysql如何实现可重入锁
创建一个保存锁记录的表,出自MySQL面试题 | 小林coding
比如锁的名称,存储的当前持有锁的线程名称,锁的可重入次数
开启事务:判断当前的记录(锁)是否存在,不存在则去加锁,存在并且持有者是同一个线程,那么我就可重入update一下,给他更新
提交事务
解锁逻辑:
开启事务
执行SQL select 查找是否有记录,如果记录存在且持有者是同一个线程那么就去--,
如果记录存在,且持有者是同一个线程,且可重入的次数小于等于0,那么就去完全释放锁。 delete对应的锁名字就好
mysql的存储引擎
Innodb是mysql的默认引擎,具有ACID事务支持,行级锁,外键约束等支持(默认聚簇索引)
MyISAM:MyISAM是mysql的另一种常见存储引擎,具有较低的存储空间和内存消耗。不支持以上如acid等操作(非聚簇索引)
Memory:(不重要):性能高,但是不是持久的
冷备:定期将主数据中心的数据库文件备份到其他数据中心,冷备不提供实时服务,当丢失数据时候,可以通过冷备恢复数据,以保证数据安全
热备:通过数据库主从复制或者binlog订阅技术,对主数据中心进行实时备份,热备提供实时任务,当主数据中心不可用的时候,热备可以自动接管业务,保证业务不间断运行,用户端对主备切换无感知
同城机房:物理距离比较近,使用专线连接,虽然跨数据中心访问延迟比单个数据中心要大,但是可接受
异地机房:异地的数据中心物理距离远,网络延迟,就算你设置光纤一个来回也是10ms,中间还有路由器,交换机等设备,抖动很容易延迟到1s
应用在操作数据库时候,要求读写分离
原则就近访问
两地三中心
两个城市,三个数据中心,两个数据中心在一个城市并且同时提供服务,第三个做异地,灾备,防止数据丢失
抵御地域性故障,通过冷备份需要时间
索引适合数据量比较大,查询比较频繁,比如where,orderby,区分度高(身份证),字符串前缀,联合索引
打开慢查询日志(查找超过阈值,根据explain)
事务
事务原子性的实现undolog回滚性日志,连续N个连续的sql操作失败了一个通过undo log给前面的操作全部回滚,事务提交之后,如果数据库崩溃了,数据丢失了咋办,事务持久性,持久性通过redo_log,即便Mysql没有持久化到磁盘中,也能读取redo_log,所以可以说让Mysql有一个崩溃恢复的能力,redo_log怎么保证刷盘呢?(他怎么保证持久化)
隔离性怎么实现,需要用MVCC+锁配合undolog实现,(除了原子性,持久性隔离性之外,事务还要保证一致性,保证其他三个就能保证一致性)
不可重复读强调的是多次读取的数据值不同,幻读强调的是数据条数的增减
读已提交:只能读到其他事务已经提交的数据 -脏读其他事务没提交的你读取不到(本质每次select就生成一个新的read view,每次就能读到已经提交的数据版本
但是无法解决不可重复读和幻读的问题
可重复读默认隔离界别(第一次读会有快照,快照其他事务的修改,对于当前事务是不可见的,每次读快照,保证统一时间内,两次读到的数据是一样的,解决了不可重复读的问题
MVCC多版本并发控制,维护数据的多个版本,
数据库三大日志
什么是undo log,undo log有什么用,什么是redo log redolog有啥用,为啥要刷盘redolog,为啥不直接刷盘buffer pool
什么是bin log ,bin log有什么用,什么是两阶段提交,如何保证redo log和bin log的一致性,
MYSQL有事务,事务特性之一就是原子性,执行一系列SQL,要么全部成功,要么全部失败,后面的SQL失败了,已经执行了也要回滚
问题来了,我数据都修改了,怎么回滚到没有修改的版本呢?这个时候就需要保存数据的不同版本了,每修改一次,就把原始的数据版本保存下来,把不同版本,通过一个回滚指针串起来,
通过一个回滚指针串起来,这就叫undo log版本链,也就是事务执行的过程中修改的数据,MYSQL会把旧的数据记录到undo log日志里面,如果事务正常提交,那就结束,如果因为异常或者执行了手动回滚,这种操作,那就通过undo log去找到旧版本的数据回滚,这也就是为啥说undo log可以保证事务的原子性, undo log第二个作用就是配合readView和表的隐藏字段去实现MVCC(MVCC执行普通select语句,就会对比事务id和readView,来查看这个数据版本,对当前事务是否可见,不可见,就沿着undo log版本链,继续查找当前事务可见的一个数据版本
每次从磁盘读写数据太慢了,写业务代码时候,查数据太慢了,咋办?
一般加一层缓存(CPU执行速度那么快,内存速度那么慢,那咋办,CPU三级缓存,(MYSQL设计了一个缓冲池叫buffer pool) MYSQL存数据以页为单位的,一个页16kb,每查询一条数据,就会把硬盘这一页的数据加载出来,把数据页放到buffer pool里面,问题来了,假如查一条数据,把数据放到缓存中不就行了。
为什么存储一个页的原因?(不至于把一个数据页的全部都读出来,放到这个buffer pool里面),程序的空间局部性原理(也就是说一个内存位置被访问了,意味着未来很有可能附近的内存位置都会被访问),因为代码里面大量使用数组这种连续结构,数组第一个位置访问了,第二,三个位置,都会被访问
同样的一些管理系统里面分页展示了很多数据,(如同抖音的一直下滑)
MYSQL一次把一个页的数据放到buffer pool中,对于连续取数据来说,命中率很高,利用了程序的一个空间局部性原理
后续取数据,先从buffer pool里面取,没有再去磁盘里面读,写数据也是先写入到buffer pool,但是不会立刻刷盘,而是把修改的页标记为脏页,然后由后台线程在某个时间内,把脏页刷盘,
问题buffer pool是在内存的,他没有立即刷盘,MYSQL要是挂了,那么数据不久丢了吗?
因此有了redo log,MYSQL每次把某个磁盘页做了什么样子的修改,记录到redo log中,然后呢事务提交之后,就刷盘redo log,如果buffer pool中的数据未刷盘就宕机了, 就可以读取redo log来恢复数据,这就是为什么说redo log能够保证事务的持久性,让MYSQL能做到崩溃恢复,
为什么修改了buffer pool之后不直接刷盘呢? 而是去写redo log ,去刷盘redo log,
因为buffer pool刷盘是随机IO,刷盘时候,需要找到某个磁盘页,然后去修改再去找另外的磁盘页,再去修改,本来磁盘就慢,随机IO更慢了
redo log只记录在哪个磁盘位置,做了怎么样的修改,刷盘的时候,只需要往redo log日志后面追加就好了,这个是顺序io,他不需要去找这个磁盘页,他磁头往一个方向去移动就可以了,
这就是为什么redo log日志要去记录数据页的物理修改,而不是直接去记录数据,因此只要redo log一刷盘,即便MYSQL崩溃了,数据也可以恢复,事务的持久性就有了保证
redo log不是直接写入磁盘的,他也有自己的的缓存,叫redo log buffer
redo log会写入redo log buffer,然后统一把redo log buffer中的数据刷盘到磁盘中,MYSQL中,有一个参数叫,innodb_flash_log_and_trx_commit这个参数就是控制redo log一个刷盘时间的,如果参数的值为0,事务提交的时候会把redo log的数据放到redo log buffer但并不会进行刷盘(危险-只是放入缓冲池,如果mysql宕机,redo log就会丢失数据)如果值为1,事务提交的时候,就会把redo log数据刷入磁盘,刷盘完成之后,才告诉客户端事务执行成功了,这样就能保证事务只要完成,即便MYSQL崩溃了,数据也不会丢失,一般情况下设置为1,
值为2,事务提交,就会把redo log的数据写入操作系统的文件缓存里面,写入page cache,操作系统本身对文件也是有缓存的,缓存就是page cache,数据写入page cache之后,操作系统会在某一个时间,真正把这个数据写入磁盘中,只要操作系统不崩溃,就能保证持久性。但是假如电脑断电了,还是g.
bin log日志
redo log是否能做备份或者主从 ,redo log是循环写,日志空间的大小是固定的,全部写满就从头再开始写,边写边擦除,它只能记录事务提交之后,没有被刷盘的那个数据已经刷盘的,会从redo log中慢慢擦除掉的,所以redo log是事务级别的数据记录,而不是数据库级别的数据记录,只可以做那些断电,或者数据库故障导致buffer pool数据未刷盘的这种数据恢复,不能做数据库全量的数据恢复,要做备份恢复,或者要主从同步,只要你是数据库的变更,都会记录bin log日志,redolog是循环写,binlog是追加写,记录的是全量日志,redolog 可以理解为物理日志,在某个数据页上做什么修改,binlog是逻辑日志,记录的内容类似于SQL语句本身,bin log非常适合做这种备份恢复,或者主从同步, bin log也有缓存 -bin logcache 执行时候会先把bin log日志,写入cache,提交的时候,就把bin log cache刷到磁盘中,
通过mysql日志设计-持久化就去搞日志,连续写的日志搞cache,先去写cache,再去异步刷盘通过日志就能做备份恢复,主从同步,(redis的rdb和aof也是这个道理)
假如redo log和bin log都要刷盘,一个刷盘成功,一个刷盘失败,两份日志不一样,咋办,为了解决两份日志之间一致性问题,mysql将redo log拆分成了prepare和commit,两阶段提交
假如写入redo log异常了,那么prepare异常了,redo log和bin log都没有,就直接回滚事务,事务没有提交成功
写入binlog异常,MYSQL根据redo log进行数据恢复的时候发现redo log处于prepare阶段,并没有对应的bin log日志,那么回滚事务
如果redo log设置commit时候异常了,MYSQL发现redo log是prepare阶段但能找到对应的bin log日志 bin log 和redo log就一致的的(MYSQL也会认为数据是完整的)所以直接提交事务,两阶段提交最终还是看bin log,只要bin log刷盘了那么就可以提交事务
redo log和bin log,