最近闲来无事,整理了一波Mysql的资料,欢迎大家来围观!!!
1、Mysql中的MyISAM与InnoDB的区别?
(1)InnoDB存储引擎支持事务,而MyISAM不支持事务; 白嫖资料 (2)InnoDB支持行级锁,而MyISAM只支持表级锁;
( InnoDB行锁是通过给索引加锁实现的,即只有通过索引条件检索数据,InnoDB才使用行级锁,否则将使用表级锁!行级锁在每次获取锁和释放锁的操作需要比表级锁消耗更多的资源。
MySQL表级锁有两种模式:表共享读锁和表独占写锁。就是说对MyIASM表进行读操作时,它不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写操作;而对MyISAM表的写操作,会阻塞其他用户对同一表的读和写操作。)
(3)InnoDB支持外键,而MyISAM不支持外键;
(4)InnoDB不保存数据库表中表的具体行数,而MyISAM会保存;
( 也就是说,执行 select count() from table 时,InnoDB要扫描一遍整个表来计算有多少行,而MyISAM只需要读出保存好的行数即可(内部维护了一个计算器,可以直接调取)。【注】:当count()语句包含where条件时,两种表的操作是一样的。也就是上述介绍到的InnoDB使用表锁的一种情况。)
对于select ,update ,insert ,delete 操作:
如果执行大量的SELECT,MyISAM是更好的选择(因为MyISAM不支持事务,使得MySQL可以提供高速存储和检索,以及全文搜索能力);
如果执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表(因为InnoDB支持事务,在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了)。
2、InnoDB存储引擎的四大特性?
插入缓冲、二次写、自适应哈希索引、预读
(1)插入缓冲:
一般情况下,主键是行唯一的标识符。通常应用程序中行记录的插入顺序是按照主键递增的顺序进行插入的。因此,插入聚集索引一般是顺序的,不需要磁盘的随机读取。因为,对于此类情况下的插入,速度还是非常快的。
如果索引是非聚集的且不唯一,在进行插入操作时,数据的存放对于非聚集索引叶子节点的插入不是顺序的,这时需要离散地访问非聚集索引页,由于随机读取的存在而导致了插入操作性能下降。(这是因为B+树的特性决定了非聚集索引插入的离散性。)
插入缓冲对于非聚集索引的插入和更新操作,不是每一次直接插入索引页中,而是先判断插入的非聚集索引页是否在缓存池中。如果在,则直接插入;如果不在,则先放入一个插入缓冲区中,好似欺骗数据库这个非聚集的索引已经插入到叶子结点了,然后再以一定的频率执行插入缓冲和非聚集索引页子节点的合并操作,这时通常能将多个插入合并到一个操作中(因为在一个索引页中),这就大大提高了对非聚集索引执行插入和修改操作的性能。
插入缓冲的使用要满足两个条件:
索引是辅助索引 索引不是唯一的 (辅助索引不能是唯一的,因为在把它插入到插入缓冲时,我们并不去查找索引页的情况。如果去查找肯定又会出现离散读的情况,插入缓冲就失去了意义。) 存在的问题:白嫖资料
在写密集的情况下,插入缓冲会过多的占用缓冲池内存,默认情况下最大可以占用1/2的缓冲池内存。
(2)二次写
当数据库宕机时,可能发生数据库正在写一个页面,而这个页只写了一部分的情况,我们称之为部分写失效。当写入失效发生时,先通过页的副本来还原该页,再重做日志,这就是两次写。
doublewrite步骤:
当一系列机制(main函数触发、checkpoint等)触发数据缓冲池中的脏页进行刷新时,并不直接写磁盘,而是会通过memcpy函数将脏页拷贝到内存中的doublewrite buffer,之后通过doublewrite buffer再分两次、每次1MB顺序写入共享表空间的物理磁盘上。 然后马上调用fsync函数,同步脏页进磁盘。在这个过程中,doublewrite页的存储是连续的,因此写入磁盘为顺序写,性能很高在完成doublewrite页的写入后,再将doublewrite buffer中的页写入到各个表空间文件中,此时的写入则是离散的。 如果操作系统在将页写入磁盘的过程中崩溃了,在恢复过程中,InnoDB存储引擎可以从共享表空间中的doublewrite中找到该页的一个副本,将其拷贝到表空间文件,再应用重做日志,就完成了恢复过程。因为有副本所以也不担心表空间中数据页是否损坏。
(3)自适应哈希索引
InnoDB存储引擎会监控对表上索引的查找,如果观察到建立哈希索引可以带来速度的提升,则建立哈希索引,所以称为自适应的。自适应哈希索引通过缓冲池的B+树构造而来,因此建立的速度很快,而且不需要将整个表都建哈希索引,InnoDB存储引擎会自动根据访问的频率和模式来为某些页建立哈希索引。
(4)预读
InnoDB 提供了两种预读的方式,一种是 Linear read ahead,由参数innodb_read_ahead_threshold控制,当你连续读取一个 extent 的 threshold 个 page 的时候,会触发下一个 extent 64个page的预读。另外一种是Random read-ahead,由参数innodb_random_read_ahead控制,当你连续读取设定的数量的page后,会触发读取这个extent的剩余page。 InnoDB 的预读功能是使用后台线程异步完成的。
3. InnoDB如何保证事务的四大特性?
MySQL的存储引擎InnoDB使用重做日志(redo log)保证一致性与持久性,回滚日志(undo log)保证原子性,使用各种锁来保证隔离性。
4. MySQL中的重做日志(redo log),回滚日志(undo log),以及二进制日志(binlog)?
MySQL中有六种日志文件,分别是:
重做日志(redo log) 回滚日志(undo log) 二进制日志(binlog) 错误日志(errorlog) 慢查询日志(slowquery log) 一般查询日志(general log) 中继日志(relay log)
其中重做日志和回滚日志与事务操作息息相关,二进制日志也与事务操作有一定的关系。 白嫖资料 事务是如何通过日志来实现的? Undo 记录某 数据 被修改 前 的值,可以用来在事务失败时进行 rollback; Redo 记录某 数据块 被修改 后 的值,可以用来恢复未写入 data file 的已成功事务更新的数据。 即,
Redo Log 保证事务的持久性 Undo Log 保证事务的原子性(在 InnoDB 引擎中,还用 Undo Log 来实现 MVCC) 比如某一时刻数据库 DOWN 机了,有两个事务,一个事务已经提交,另一个事务正在处理。数据库重启的时候就要根据日志进行前滚及回滚,把已提交事务的更改写到数据文件,未提交事务的更改恢复到事务开始前的状态。即通过 redo log 将所有已经在存储引擎内部提交的事务应用 redo log 恢复,所有已经 prepared 但是没有 commit 的事务将会应用 undo log 做回滚。 重做日志(redo log): redo log在事务没有提交前,会记录每一个修改操作变更后的数据。主要是防止在发生故障的时间点,尚有脏页未写入磁盘。在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。(作用)
在事务提交前,只要将 Redo Log 持久化即可,不需要将数据持久化。当系统崩溃时,系统可以根据redo Log的内容,将所有数据恢复到最新的状态。(持久化:先将重做日志写入缓存,再刷新(fsync)到磁盘)
重做日志是物理日志,记录的是对于每个页的修改。事务开始后Innodb存储引擎先将重做日志写入缓存(innodb_log_buffer)中。然后会通过以下三种方式将innodb日志缓冲区的日志刷新到磁盘。
Master Thread每秒一次执行刷新Innodb_log_buffer到重做日志文件。 每个事务提交时会将重做日志刷新到重做日志文件。 当重做日志缓存可用空间少于一半时,重做日志缓存被刷新到重做日志文件 当事务提交时,必须先将该事务的所有日志写入到重做日志文件进行持久化。
1、内容:
物理格式的日志,记录的是物理数据页面的修改的信息,其redo log是顺序写入redo log file的物理文件中去的。
2、redo log是什么时候写盘的?
是在事物开始之后逐步写盘的。
事务开始之后就产生redo log,redo log的写盘并不是随着事务的提交才写入的,而是在事务的执行过程中,便开始写入redo log文件中。(先将重做日志写入缓存,将日志缓冲区的日志刷新到磁盘,写入磁盘的方式有上面3种)
【注】即使某个事务还没有提交,Innodb存储引擎仍然每秒会将重做日志缓存刷新到重做日志文件。这一点是必须要知道的,因为这可以很好地解释再大的事务的提交(commit)的时间也是很短暂的。
3、什么时候释放:
当对应事务的脏页写入到磁盘之后,redo log的使命也就完成了,重做日志占用的空间就可以重用(被覆盖)。
回滚日志(undo log): 保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。(作用)
事务发生异常需要回滚,这时就需要回滚日志。回滚日志不同于重做日志,它是逻辑日志,对数据库的修改都逻辑的取消了。当事务回滚时,它实际上做的是与先前相反的工作。对于每个INSERT,InnoDB存储引擎都会完成一个DELETE;对于每个UPDATE,InnoDB存储引擎都会执行一个相反的UPDATE。
未提交的事务和回滚了的事务也会产生重做日志。InnoDB存储引擎会重做所有事务包括未提交的事务和回滚了的事务,然后通过回滚日志回滚那些未提交的事务。使用这种策略需要回滚日志在重做日志之前写入磁盘,使得持久化变得复杂起来。为了降低复杂度,InnoDB存储引擎将回滚日志作数据,记录回滚日志的操作也会记录到重做日志中。这样回滚日志就可以像数据一样缓存起来,而不用在重写日志之前写入磁盘了。 白嫖资料 1、内容:
逻辑格式的日志,在执行undo的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。
2、什么时候产生?
事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性
3、什么时候释放?
当事务提交之后,undo log并不能立马被删除,而是放入待清理的链表,由purge线程判断是否由其他事务在使用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。
二进制日志(bin log): 1、作用:
用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。 用于数据库的基于时间点的还原。
2、内容:
逻辑格式的日志,可以简单认为就是执行过的事务中的sql语句。
但又不完全是sql语句这么简单,而是包括了执行的sql语句(增删改)反向的信息,也就意味着delete对应着delete本身和其反向的insert;update对应着update执行前后的版本的信息;insert对应着delete和insert本身的信息。
在使用mysqlbinlog解析binlog之后一些都会真相大白。 因此可以基于binlog做到类似于oracle的闪回功能,其实都是依赖于binlog中的日志记录。
3、什么时候产生:
事务提交的时候,一次性将事务中的sql语句(一个事物可能对应多个sql语句)按照一定的格式记录到binlog中。这里与redo log很明显的差异就是redo log并不一定是在事务提交的时候刷新到磁盘,redo log是在事务开始之后就开始逐步写入磁盘。
因此对于事务的提交,即便是较大的事务,提交(commit)都是很快的,但是在开启了bin_log的情况下,对于较大事务的提交,可能会变得比较慢一些。这是因为binlog是在事务提交的时候一次性写入的造成的,这些可以通过测试验证。
4、什么时候释放:
binlog的默认是保持时间由参数expire_logs_days配置,也就是说对于非活动的日志文件,在生成时间超过expire_logs_days配置的天数之后,会被自动删除。
binlog与redolog的区别? 在MySQL数据库中还有一种二进制日志,其用来基于时间点的还原及主从复制。从表面上来看其和重做日志非常相似,都是记录了对于数据库操作的日志。但是,从本质上来看有着非常大的不同。 首先重做日志是在InnoDB存储引擎层产生的,而二进制日志是在MySQL数据库的上层产生的。其次,两种日志记录的内容形式不同。二进制日志是一种逻辑日志,其记录的是对应的SQL语句。而重做日志是物理日志,记录的是每个页的修改。此外,两种日志记录写入磁盘的时间点不同,二进制日志只在事务提交完成后进行一次写入,重做日志在事务进行时不断地写入。
3、什么是事务?
事务就是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位。事务是数据库维护数据一致性的单位,在每个事务结束时,都能保持数据一致性。
4、数据库事务的四大特性?
原子性、一致性、隔离性、持久性 (ACID)
原子性:是指整个数据库事务是不可分割的单位。只有使事务中的所有数据库操作都成功,才算整个事务成功。如果事务中任何一个sql语句执行失败,那么已经执行的sql语句也必须撤销,事务状态退回到执行事务之前的状态。 一致性:一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态。在事务开始之前和事务结束之后,事务的完整性约束没有被破坏。 隔离性:一个事务的影响在该事务提交前对其他事物都不可见。——这通过锁来实现 持久性:事务一旦提交,其结果就是永久性的。 (隔离性由锁来实现;原子性、一致性和持久性通过数据库的redo和undo来完成。)
5、不考虑事务的隔离性,会发生几种问题?
通过锁可以实现事务隔离性的要求,使得事务可以并发地工作。因为事务隔离性的要求,锁会带来3种问题:丢失更新、脏读、不可重复读。
丢失更新: 白嫖资料 指一个事务正在访问修改数据,与此同时另一个事务也在访问修改此数据,两个事务互相不知道对方的存在。假如在是事务A修改数据前事务B已经修改过1次数据,那么事务A最终只能查询到假数据,丢失了更新操作。
解决方案:
悲观锁的方式: 加锁,建议最后一步更新数据的时候加上排它锁,不要在一开始就加锁。执行到了最后一步更新,首先做一下加锁的查询确认数据有没有没改变,如果没有被改变,则进行数据的更新,否则失败。 一定要是做加锁的查询确认,因为如果你不加锁的话,有可能你在做确认的时候数据又发生了改变。
乐观锁的方式:使用版本控制实现。
脏读:
一个事务读取了另一个事务未提交的数据,那这个读取就是脏读。
解决方法 : 把数据库的事务隔离级别调整到read commited。
白嫖资料
不可重复读:
不可重复读是指在一个事务内多次读同一数据,在这个事务还没有结束时,另外一个事务也访问并修改该同一数据,那么在第一个事务的两次读数据之间,由于第二个事务的修改,第一个事务两次读到的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读。
如何避免:InnoDB存储引擎中,通过使用Next-Key Lock算法来避免不可重复读的问题。在Next-Key Lock算法下,对于索引的扫描,不仅仅是锁住扫描到的索引,而且还能锁住这些索引覆盖的范围。因此对于这个范围内的插入都是不允许的。InnoDB存储引擎的默认事务隔离级别是READ REPEATABLE,采用Next-Key Lock算法,就避免了不可重复读的现象。
解决办法:把数据库的事务隔离级别调整到 REPEATABLE READ , 读取时候不允许其他事务修改该数据,不管数据在事务过程中读取多少次,数据都是一致的。
幻读:
是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
如何避免:Repeatable read及以上级别通过间隙锁来防止幻读的出现,即锁定特定数据的前后间隙让数据无法被插入。
6、MySQL数据库提供的四种隔离级别? read uncommitted(读未提交) read committed(读已提交) repeatable read(可重复读):InnoDB的默认隔离级别 serializable(串行)
7、有多少种日志? 错误日志 :记录出错信息,也记录一些警告信息或者正确的信息。 查询日志 :记录所有对数据库请求的信息,不论这些请求是否得到了正确的执行。 慢查询日志:设置一个阈值,将运行时间超过该值的所有SQL语句都记录到慢查询的日志文件中。 二进制日志:记录对数据库执行更改的所有操作。 中继日志 事务日志