最近在学习mysql的优化方面,这里当然逃不开mysql的引擎了,学的时候自己就是分析了一下这两个的优缺点,和什么情况用MyISAM,什么情况用Innodb。昨天接到阿里电话面试,当问道这两个数据库引擎时,我开心的不得了,这两个我分析过的呀。然而面试官听我说了以后,说了句你说MyISAM查询速度比Innodb快,能告诉我为什么吗。听到这,一时语塞,我只知道是这样,至于为什么,天呐,没研究呀。当面试完了以后,自己就开始分析起来了,这里做一下笔记,方便以后自己复习。

首先还是对比一下这两个的区别吧:

mysql之MyISAM和InnoDB

再说说一些细节吧:

1.InnoDB不支持FULLTEXT类型的索引。

2.MyISAM内置了一个计数器,count(*)时它直接从计数器中读,而InnoDB必须扫描全表。但是

3..对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。

4.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。

5.LOAD   TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

6.InnoDB的行锁并不是绝对的,当索引失效时,会导致行锁变成表锁。至于什么是索引失效,具体内容挺多的,我下一篇会详细写的。

7.InnoDB的AUTOCOMMIT默认是打开的,即每条SQL语句会默认被封装成一个事务,自动提交,这样会影响速度,所以最好是把多条SQL语句显示放在begin和commit之间,组成一个事务去提交。

8.InnoDB会出现死锁,而MyISAM不会。为什么呢,Mysql行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql语句操作了主键索引,那么Mysql就会锁定这个主键索引,如果sql语句操作的是非主键索引,那么Mysql会先锁定这个非主键索引,再去锁定主键索引。死锁”举例分析:表Test:(ID,STATE,TIME) 主键索引:ID 非主键索引:STATE当执行"UPDATE STATE =1011 WHERE STATE=1000" 语句的时候会锁定STATE索引,由于STATE 是非主键索引,所以Mysql还会去请求锁定ID索引当另一个SQL语句与语句1几乎同时执行时:“UPDATE STATE=1010 WHERE ID=1” 对于语句2 Mysql会先锁定ID索引,由于语句2操作了STATE字段,所以Mysql还会请求锁定STATE索引。这时。彼此锁定着对方需要的索引,又都在等待对方释放锁定。所以出现了"死锁"的情况。


好,接下来看看开始提出的问题,为啥MyISAM比InnoDB查询速度快:

一句话,InnoDB在做查询的时候,要维护的东西比MyISAM多很多

1.InnoDB缓存索引和真实数据,MyISAM只缓存索引,这中间还有缓存数据换进换出的减少。

2.innodb寻址要映射到块,再到行,MYISAM记录的直接是文件的OFFSET(偏移量),定位比INNODB要快

3.INNODB还需要维护MVCC一致;虽然你的场景没有,但他还是需要去检查和维护MVCC (Multi-Version Concurrency Control)多版本并发控制 ,那什么是多MVCC呢,看到一个官方翻译,挺好理解的,我copy下来了:

多版本并发控制(简称MCC或者MVCC),是一种并发控制思想,通常被用于DBMS中去保证并发连接数据库,或者去实现事务内存编程。如果在一个库中,有人读,同时也有人写,很可能读操作会获取到写入一部分的内容,或者不一致的数据片段。有好几种方法可以解决这个问题,都采用并发控制思想。最简单的方法是加锁,让读操作一直等待直到写入结束,但这会导致读写非常慢。MVCC采用另一种思路,访问数据库的每个用户都将看到一个特定时刻的数据库快照。写操作进行的修改,不会被其他用户看到,直至修改完成(在数据库中,直至事务被提交)。一个支持MVCC的数据库更新某一项数据的时候,它不会直接用新数据去覆盖原数据,而是将原数据标记为废弃,并且把新数据写在其他地方,这样就有多版本的数据同时被存储,但是只有一个是最新的。MVCC允许一个读会话开启之后,连接依然可以查看数据,即使它被其他操作修改或者删除。MVCC让数据库避免直接填写内存的空洞,或磁盘的结构(即被标记为脏数据的部分),一般请求系统周期性换出将脏数据删除。对于一个文件类型的数据库来说,系统通过把整个文件写入相似的磁盘区,更新完成后,整个文件被重写的方式来修改磁盘结构,而非一点一点截取或被链接在一个完全不同的磁盘结构。MVCC提供时间一致性读。MVCC下的读事务一般用一个时间戳或者事务ID来决定读取什么样的数据状态,和哪个版本的数据。这避免了为读事务加锁,因为写操作被独立执行在老本本的数据上,而不是通过发起锁或者互斥进程。写影响一个将来版本的数据,而不是读操作正在进行的事务id版。任何数据都一致的,因为写影响下一个事务id。

注释:
InnoDB:通过为每一行记录添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。但是InnoDB并不存储这些事件发生时的实际时间,相反它只存储这些事件发生时的系统版本号。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否相同。让我们来看看当隔离级别是REPEATABLEREAD时这种策略是如何应用到特定的操作的:
  SELECT InnoDB必须每行数据来保证它符合两个条件:
  1、InnoDB必须找到一个行的版本,它至少要和事务的版本一样老(也即它的版本号不大于事务的版本号)。这保证了不管是事务开始之前,或者事务创建时,或者修改了这行数据的时候,这行数据是存在的。

  2、这行数据的删除版本必须是未定义的或者比事务版本要大。这可以保证在事务开始之前这行数据没有被删除。


参考文章:

http://www.cnblogs.com/wyeat/p/translation_mvcc.html

http://www.cnblogs.com/fwqblogs/p/6645274.html

http://www.2cto.com/database/201404/291438.html

http://blog.csdn.net/xifeijian/article/details/20316775

相关文章: