数据库设计三大范式:
(1)确保数据库表字段的原子性,即字符不可再分性。
(2)一个表必须有主键,非主键列必须完全依赖于主键,不能部分依赖。
(3)非主键必须直接依赖于主键,不能间接依赖。
bin log二进制日志,redo log重做日志(持久性),undo log回滚日志(原子性)。
二进制日志会记录所有的日志,包括存储引擎端的日志。重做日志只记录存储引擎的日志。
undo log是回滚日志。实现回滚,并且可以通过undo log回溯到某个特定版本的数据,实现mvcc。
redo log是重做日志。是存储引擎级别的日志,不管事务是否提交都会被记录,用于数据恢复。把innodb_flush_log_at_tx_commit设置成1,那么执行commit的时候会将redo log同步写到磁盘。
bin log是二进制日志。是数据库级别的文件,会记录执行修改的所有操作,但是select和show这种查询语句不会记录。
bin log和redo log的区别:一个会记录所有日志,一个只记录存储引擎自身的事务日志。一个只在事务提交前写入,一个在事务进行中会不断写入。一个记录sql语句原始逻辑,一个记录在页上做了什么修改。
一条SQL查询语句的执行:连接器(连接数据库)、查询缓存(在数据更新的时候会降低效率,已经不用了)、分析器(做什么)、优化器(怎么做更好)、执行器。
慢查询日志有一个rows_examined字段,表示这个语句在执行过程中扫描了多少行,这个值即使在执行器每次调用引擎获取数据行的时候累加的。
上述都属于server层,还有存储引擎层,是负责存储数据,提供读写接口。
一条SQL更新语句的执行:连接器、分析器(知道是更新语句)、优化器(知道ID索引)、执行器(找到行更新)
此外,更新流程还涉及两个重要的日志模块:redo log重做日志、bin log归档日志。
(1)物理日志redo log:如果有人要赊账,老板要有黑板和账本一起配合才能加快效率。(保证事务持久性)
如果只有账本,人家要赊账,就要找到账本记录,计算,再写结果,卖的时候很麻烦。还是先在黑板写比较方便。
黑板和账本的配合就是WAL,即write-ahead-logging技术,就是先写日志,再写磁盘。
需要更新的时候,InnoDB引擎就先把记录写到redo log(黑板)上,并更新内存(大脑意念),这个时候更新完成。然后InnoDB引擎在适当的空闲的时候将操作记录更新到磁盘里面(账本)。
redo log是固定大小的,就像黑板写满了,老板就要放下手中的活,更新账本,擦掉黑板,腾出空间。
write pos是当前记录的位置,checkpoint是当前擦除的位置。二者之间是黑板空着的位置,记录操作,如果write pos追上checkpoint,说明黑板满了,这时候不能执行更新,得停下来擦掉记录,推进checkpoint。
有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交得记录都不会丢失,这个能力叫做crash-safe。
比如老板忘记记录,但是黑板有,停业几天依旧可以记录。
redo log用于保证crash-safe的能力。innodb_flush_log_at_trx_commit这个参数设置成1的时候,表示每次事务的redo log都直接持久化到磁盘,这样可以保证MySQL异常重启之后数据不丢失。
(2)逻辑日志binlog:(最开始没有InnoDB引擎,只实现binlog无法实现crash-safe功能)
redo log是InnoDB引擎特有的日志,而server层也有自己的日志,叫做binlog即归档日志。
redo log是物理日志,记录在某个数据页做什么修改;bin log是逻辑日志,记录这个语句的原始逻辑。
redo log是循环写的,空间固定会用完;bin log是可以追加写入的,不会覆盖以前的日志。
redo log的写入分成两个步骤:prepare和commit,这就是两阶段提交。为了让两份日志之间的逻辑保持一致。(反证法)
binlog有sync_binlog参数,设置成1的时候,表示每次事务的binlog都持久化到磁盘,可以保证MySQL异常重启之后binlog不丢失。