赞
踩
大体来说,MySQL分为Server层和存储引擎层两部分。
负责跟客户端建立连接、获取权限、维持和管理连接。
-- 建立连接
mysql -h$ip -P$port -u$user -p
-- 查询连接
show processlist
一个用户成功建立连接后,即使你用管理员账号对这个用户的权限做了修改,也不会影响已经存在连接的权限。只有再新建的连接,才会使用新的权限设置。
MySQL执行一个查询请求后,会把查询结果以key(查询语句)-value(查询结果)的形式存入查询缓存中,下次查询相同语句会直接从查询缓存中返回结果,效率很高。
但查询缓存弊大于利,建议关闭。甚至MySQL 8.0 版本已将查询缓存删掉了,没有这个功能了。
因为查询缓存失效非常频繁,只要对某个表进行更新操作,这个表上所有查询缓存都会被清空。
确定最终执行计划:
返回结果:
如果每次更新时,都需要在磁盘中找到对应的记录,然后更新并将新数据写进磁盘,整个过程的IO成本、查找成本都很高。
为了提升效率,InnoDB引擎使用了WAL 技术(Write-Ahead Logging),即先写日志,再写磁盘。
具体来讲,当有一条记录需要更新时,InnoDB引擎会先把记录写到redo log中,并更新内存,这时更新就算已经完成。在系统比较空闲时,再把这个更新操作记录到磁盘里(redo log文件名:ib_logfile+数字)。
redo log 是固定大小的,可以配置。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示:
write pos 是当前记录的位置,checkpoint 是当前要擦除的位置(在擦除记录前要把记录更新到磁盘的数据文件中),它们都是往后推移并且循环的。
write pos 和 checkpoint 之间空的部分可以用来记录新的操作,如果两者重合,则不能再执行新的更新,需要把一些数据写进磁盘,让checkpoint 往后移动才行。
有了 redo log,InnoDB 就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为 crash-safe。
redo log 的写入机制:
innodb_flush_log_at_trx_commit
参数控制写入磁盘的策略。innodb_flush_log_at_trx_commit=0
,表示每次事务提交时都只是把 redo log 留在 redo log buffer 中 ;innodb_flush_log_at_trx_commit=1
,表示每次事务提交时都将 redo log 直接持久化到磁盘;innodb_flush_log_at_trx_commit=2
,表示每次事务提交时都只是把 redo log写到 page cache。建议:innodb_flush_log_at_trx_commit=1
此外,没有提交的事务也会被MYSQL写入到磁盘:
innodb_log_buffer_size
一半的时候,后台线程会主动写盘来减少 redo log buffer的空间占用redo log是InnoDB引擎特有的日志,Service层也有自己的日志:binlog(归档日志)。
为什么要有两份日志呢?
因为最开始 MySQL 里并没有 InnoDB 引擎。MySQL 自带的引擎是 MyISAM,但是 MyISAM 没有 crash-safe 的能力,binlog 日志只能用于归档。InnoDB是另外的公司以插件形式引入MySQL的,为了弥补其没有crash-safe能力而实现的redo log。
两种日志主要有三个不同点:
binlog 的写入机制:
sync_binlog=0
,表示每次提交事务都只 write,不 fsync;sync_binlog=1
,表示每次提交事务都会执行 fsync;sync_binlog=N(N>1)
,表示每次提交事务都 write,但累积 N在实际的业务场景中,考虑到丢失日志量的可控性,一般不建议将这个参数设成 0。但是,将 sync_binlog 设置为 N,对应的风险是:如果主机发生异常重启,会丢失最近 N 个事务的 binlog 日志。
建议:sync_binlog = 1
每次事务的binlog都持久化到磁盘
一个事务的 binlog 是不能被拆开的,不论这个事务多大,也要确保一次性写入。系统给每个线程都分配了一片 binlog cache内存,参数
binlog_cache_size
用于控制单个线程内 binlog cache 所占内存的大小。如果超过了这个参数规定的大小,就要暂存到磁盘。
这里的关键部分是,redo log 的写入拆成了两个步骤:prepare 和 commit。这就是所谓的"两阶段提交"。
为什么会有两段提交呢?是为了让两份日志之间的逻辑一致。如果不一致,则数据库的数据和用binlog恢复或者同步出来的数据会不一致。
情况1:写入redo log后,写入binlog之前崩溃,因为未commit,事务回滚,redo log也会回滚;
情况2:写入redo log,又写入binlog后,commit之前崩溃:
一个事务的binlog是由完整格式的:
他们有一个共同的数据字段XID。
情况2时,会拿redo log的XID去binlog中找对应的事务。
因为binlog不支持崩溃恢复。
MySQL原生引擎MyISAM在设计之初就没有支持崩溃恢复。binlog的目的主要用于数据复制和某些类型的增量备份,它虽然保存了全量的日志,但没有提供崩溃恢复的功能。
最重要的是,binlog是追加写的,但没有一个标志让 innoDB 判断哪些数据已经入表(写入磁盘),哪些数据还没有。
redo log 太小的话,会导致很快被写满,然后不得不强制刷redo log到磁盘,WAL机制的能力有发挥不出来。
如果几个TB的磁盘,直接将redo log设为4个文件,每个文件1GB.
innodb_log_files_in_group=4
innodb_log_file_size=1000M
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。