MyISAM 与 innoDB 的选择

一、MyISAM:默认表类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问方法) 的缩写,它是存储记录和文件的标准方法。不是事务安全的,并且不支持外键,若是执行大量的select,insert MyISAM比较适合。mysql

二、InnoDB:支持事务安全的引擎,支持外键、行锁、事务是他的最大特色。若是有大量的update和insert,建议使用InnoDB,特别是针对多个并发和QPS较高的状况。linux

 

1、表锁差别sql

MyISAM:数据库

myisam只支持表级锁,用户在操做myisam表时,select,update,delete,insert语句都会给表自动加锁,若是加锁之后的表知足insert并发的状况下,能够在表的尾部插入新的数据。也能够经过lock table命令来锁表,这样操做主要是能够模仿事务,可是消耗很是大,通常只在实验演示中使用。缓存

InnoDB :安全

Innodb支持事务和行级锁,是innodb的最大特点。服务器

事务的ACID属性:atomicity,consistent,isolation,durable。多线程

并发事务带来的几个问题:更新丢失,脏读,不可重复读,幻读。并发

事务隔离级别:未提交读(Read uncommitted),已提交读(Read committed),可重复读(Repeatable read),可序列化(Serializable)函数

四种隔离级别的比较

读数据一致性及并发反作用

 

隔离级别

读数据一致性

脏读

不可重复读

幻读

为提交读(read uncommitted)

最低级别,不读物理上顺坏的数据

已提交读(read committed)

语句级

可重复读(Repeatable red)

事务级

可序列化(Serializable)

最高级别,事务级

 

查看mysql的默认事务隔离级别“show global variables like ‘tx_isolation’; ”

Innodb的行锁模式有如下几种:共享锁,排他锁,意向共享锁(表锁),意向排他锁(表锁),间隙锁。

注意:当语句没有使用索引,innodb不能肯定操做的行,这个时候就使用的意向锁,也就是表锁

关于死锁:

什么是死锁?当两个事务都须要得到对方持有的排他锁才能完成事务,这样就致使了循环锁等待,也就是常见的死锁类型。

解决死锁的方法:

一、  数据库参数

二、  应用中尽可能约定程序读取表的顺序同样

三、  应用中处理一个表时,尽可能对处理的顺序排序

四、  调整事务隔离级别(避免两个事务同时操做一行不存在的数据,容易发生死锁)

 

2、数据库文件差别

MyISAM :

myisam属于堆表

myisam在磁盘存储上有三个文件,每一个文件名以表名开头,扩展名指出文件类型。

.frm 用于存储表的定义

.MYD 用于存放数据

.MYI 用于存放表索引

myisam表还支持三种不一样的存储格式:

静态表(默认,可是注意数据末尾不能有空格,会被去掉)

动态表

压缩表

InnoDB :

innodb属于索引组织表

innodb有两种存储方式,共享表空间存储和多表空间存储

两种存储方式的表结构和myisam同样,以表名开头,扩展名是.frm。

若是使用共享表空间,那么全部表的数据文件和索引文件都保存在一个表空间里,一个表空间能够有多个文件,经过innodb_data_file_path和innodb_data_home_dir参数设置共享表空间的位置和名字,通常共享表空间的名字叫ibdata1-n。

若是使用多表空间,那么每一个表都有一个表空间文件用于存储每一个表的数据和索引,文件名以表名开头,以.ibd为扩展名。

 

3、索引差别

一、关于自动增加

myisam引擎的自动增加列必须是索引,若是是组合索引,自动增加能够不是第一列,他能够根据前面几列进行排序后递增。

innodb引擎的自动增加咧必须是索引,若是是组合索引也必须是组合索引的第一列。

二、关于主键

myisam容许没有任何索引和主键的表存在,

myisam的索引都是保存行的地址。

innodb引擎若是没有设定主键或者非空惟一索引,就会自动生成一个6字节的主键(用户不可见)

innodb的数据是主索引的一部分,附加索引保存的是主索引的值。

三、关于count()函数

myisam保存有表的总行数,若是select count(*) from table;会直接取出出该值

innodb没有保存表的总行数,若是使用select count(*) from table;就会遍历整个表,消耗至关大,可是在加了wehre       条件后,myisam和innodb处理的方式都同样。

四、全文索引

myisam支持 FULLTEXT类型的全文索引

innodb不支持FULLTEXT类型的全文索引,可是innodb可使用sphinx插件支持全文索引,而且效果更好。(sphinx   是一个开源软件,提供多种语言的API接口,能够优化mysql的各类查询)

五、delete from table

使用这条命令时,innodb不会重新创建表,而是一条一条的删除数据,在innodb上若是要清空保存有大量数据的表,最       好不要使用这个命令。(推荐使用truncate table,不过须要用户有drop此表的权限)

六、索引保存位置

myisam的索引以表名+.MYI文件分别保存。

innodb的索引和数据一块儿保存在表空间里。

 

4、开发的注意事项

一、能够用 show create table tablename 命令看表的引擎类型。

二、对不支持事务的表作start/commit操做没有任何效果,在执行commit前已经提交。

三、能够执行如下命令来切换非事务表到事务(数据不会丢失),innodb表比myisam表更安全:alter table tablename type=innodb;或者使用 alter table tablename engine = innodb;

四、默认innodb是开启自动提交的,若是你按照myisam的使用方法来编写代码页不会存在错误,只是性能会很低。如何在编写代码时候提升数据库性能呢?

a、尽可能将多个语句绑到一个事务中,进行提交,避免屡次提交致使的数据库开销。

b、在一个事务得到排他锁或者意向排他锁之后,若是后面还有须要处理的sql语句,在这两条或者多条sql语句之间程序应尽可能少的进行逻辑运算和处理,减小锁的时间。

c、尽可能避免死锁

d、sql语句若是有where子句必定要使用索引,尽可能避免获取意向排他锁。

f、针对咱们本身的数据库环境,日志系统是直插入,不修改的,因此咱们使用混合引擎方式,ZION_LOG_DB照旧使用myisam存储引擎,只有ZION_GAME_DB,ZION_LOGIN_DB,DAUM_BILLING使用Innodb引擎。

 

5、究竟该怎么选择

下面先让咱们回答一些问题:   

◆你的数据库有外键吗?   

◆你须要事务支持吗?   

◆你须要全文索引吗?   

◆你常用什么样的查询模式?   

◆你的数据有多大?   
  
myisam只有索引缓存   
innodb不分索引文件数据文件 innodb buffer   
myisam只能管理索引,在索引数据大于分配的资源时,会由操做系统来cache;数据文件依赖于操做系统的cache。innodb无论是索引仍是数据,都是本身来管理  
  
思考上面这些问题可让你找到合适的方向,但那并非绝对的。若是你须要事务处理或是外键,那么InnoDB 多是比较好的方式。若是你须要全文索引,那么一般来讲 MyISAM是好的选择,由于这是系统内建的,然而,咱们其实并不会常常地去测试两百万行记录。因此,就算是慢一点,咱们能够经过使用Sphinx从InnoDB中得到全文索引。  
  
数据的大小,是一个影响你选择什么样存储引擎的重要因素,大尺寸的数据集趋向于选择InnoDB方式,由于其支持事务处理和故障恢复。数据库的在小决定了故障恢复的时间长短,InnoDB能够利用事务日志进行数据恢复,这会比较快。而MyISAM可能会须要几个小时甚至几天来干这些事,InnoDB只须要几分钟。  
  
操做数据库表的习惯可能也会是一个对性能影响很大的因素。好比: COUNT() 在 MyISAM 表中会很是快,而在InnoDB 表下可能会很痛苦。而主键查询则在InnoDB下会至关至关的快,但须要当心的是若是咱们的主键太长了也会致使性能问题。大批的inserts 语句在 MyISAM下会快一些,可是updates 在InnoDB下会更快一些——尤为在并发量大的时候。  
  
因此,到底你检使用哪个呢?根据经验来看,若是是一些小型的应用或项目,那么MyISAM 也许会更适合。固然,在大型的环境下使用 MyISAM 也会有很大成功的时候,但却不老是这样的。若是你正在计划使用一个超大数据量的项目,并且须要事务处理或外键支持,那么你真的应该直接使用 InnoDB方式。但须要记住InnoDB 的表须要更多的内存和存储,转换100GB 的MyISAM 表到InnoDB 表可能会让你有很是坏的体验。  
  
对于支持事务的InnoDB类型的表,影响速度的主要缘由是AUTOCOMMIT默认设置是打开的,并且程序没有显式调用BEGIN 开始事务,致使每插入一条都自动Commit,严重影响了速度。能够在执行sql前调用begin,多条sql造成一个事务(即便autocommit打开也能够),将大大提升性能。  

 

InnoDB

InnoDB 给 MySQL 提供了具备事务(commit)、回滚(rollback)和崩溃修复能力 (crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。 InnoDB 提供了行锁(locking on row level),提供与 Oracle 类型一致的不加锁读取(non- locking read in SELECTs)。这些特性均提升了多用户并发操做的性能表现。在InnoDB表中不须要扩大锁定 (lock escalation),由于 InnoDB 的列锁定(row level locks)适宜很是小的空间。 InnoDB 是 MySQL 上第一个提供外键约束(FOREIGN KEY constraints)的表引擎。  

InnoDB 的设计目标是处理大容量数据库系统,它的 CPU 利用率是其它基于磁盘的关系数据库引擎所不能比的。在技术上,InnoDB 是一套放在 MySQL 后台的完整数据库系统,InnoDB 在主内存中创建其专用的缓冲池用于高速缓冲数据和索引。 InnoDB 把数据和索引存放在表空间里,可能包含多个文件,这与其它的不同,举例来讲,在 MyISAM 中,表被存放在单独的文件中。InnoDB 表的大小只受限于操做系统的文件大小,通常为 2 GB。  
InnoDB全部的表都保存在同一个数据文件 ibdata1 中(也多是多个文件,或者是独立的表空间文件),相对来讲比较很差备份,免费的方案能够是拷贝数据文件、备份 binlog,或者用 mysqldump。  


MyISAM   
MyISAM 是MySQL缺省存贮引擎 .   
每张MyISAM 表被存放在三个文件 。frm 文件存放表格定义。 数据文件是MYD (MYData) 。 索引文件是 MYI (MYIndex) 引申。   
由于MyISAM相对简单因此在效率上要优于InnoDB..小型应用使用MyISAM是不错的选择.   
MyISAM表是保存成文件的形式,在跨平台的数据转移中使用MyISAM存储会省去很多的麻烦   
  
如下是一些细节和具体实现的差异:   
  
1.InnoDB不支持FULLTEXT类型的索引。   
2.InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,可是MyISAM只要简单的读出保存好的行数便可。注意的是,当count(*)语句包含 where条件时,两种表的操做是同样的。  
3.对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,可是在MyISAM表中,能够和其余字段一块儿创建联合索引。   
4.DELETE FROM table时,InnoDB不会从新创建表,而是一行一行的删除。   
5.LOAD TABLE FROM MASTER操做对InnoDB是不起做用的,解决方法是首先把InnoDB表改为MyISAM表,导入数据后再改为InnoDB表,可是对于使用的额外的InnoDB特性(例如外键)的表不适用。  

另外,InnoDB表的行锁也不是绝对的,若是在执行一个SQL语句时MySQL不能肯定要扫描的范围,InnoDB表一样会锁全表,例如 update table set num=1 where name like “%aaa%”  

任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优点。   

 

6、重复地总结一遍

一、MyISAM不支持事务,InnoDB是事务类型的存储引擎,当咱们的表须要用到事务支持的时候,那确定是不能选择MyISAM了。

二、MyISAM只支持表级锁,BDB支持页级锁和表级锁默认为页级锁,而InnoDB支持行级锁和表级锁默认为行级锁
 
表级锁:直接锁定整张表,在锁按期间,其余进程没法对该表进行写操做,若是设置的是写锁,那么其余进程读也不容许
 
MyISAM是表级锁定的存储引擎,它不会出现死锁问题
 
对于write,表锁定原理以下:
 
若是表上没有锁,在其上面放置一个写锁,不然,把锁定请求放在写锁队列中。
 
对于read,表锁定原理以下 :
 
若是表上没有写锁定,那么把一个读锁放在其上面,不然把锁请求放在读锁定队列中
 
当一个锁定被释放时,表可被写锁定队列中的线程获得,而后才是读锁定队列中的线程。这意味着,若是你在一个表上有许多更新,那么你的SELECT语句将等到全部的写锁定线程执行完。

行级锁:只对指定的行进行锁定,其余进程仍是能够对表中的其余行进行操做的。
 
行级锁是Mysql粒度最小的一种锁,它能大大的减小数据库操做的冲突,可是粒度越小实现成本也越大。
 
行级锁可能会致使“死锁”,那究竟是怎么致使的呢,分析缘由:Mysql行级锁并非直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,若是一条sql语句操做了主键索引,那么Mysql就会锁定这个主键索引,若是sql语句操做的是非主键索引,那么Mysql会先锁定这个非主键索引,再去锁定主键索引。
 
在UPDATE 和 DELETE操做时Mysql不只会锁定全部WHERE 条件扫描过得索引,还会锁定相邻的键值。
 
“死锁”举例分析:
 
表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索引。这时。彼此锁定着对方须要的索引,又都在等待对方释放锁定。因此出现了"死锁"的状况。
 
行级锁的优势:
 
有许多线程访问不一样的行时,只存在少许的冲突。
 
回滚时只有少许的更改
 
能够长时间锁定单一的行
 
行级锁缺点:
 
相对于页级锁和表级锁来讲占用了更多的内存
 
当表的大部分行在使用时,比页级锁和表级锁慢,由于你必须得到更多的锁
 
当在大部分数据上常用GROUP BY操做,确定会比表级锁和页级锁慢。
 
页级锁:表级锁速度快,可是冲突多;行级锁速度慢,但冲突少;页级锁就是他俩折中的,一次锁定相邻的一组记录。

三、MyISAM引擎不支持外键,InnoDB支持外键

四、MyISAM引擎的表在大量高并发的读写下会常常出现表损坏的状况
 
咱们之前作的项目就遇到这个问题,表的INSERT 和 UPDATE操做很频繁,原来用的MyISAM引擎,致使表隔三差五就损坏,后来更换成了InnoDB引擎。
 
其余容易致使表损坏缘由:
 
服务器忽然断电致使数据文件损坏,强制关机(mysqld未关闭状况下)致使表损坏
 
mysqld进程在写入操做的时候被杀掉
 
磁盘故障
 
表损坏常见症状:
 
查询表不能返回数据或返回部分数据
 
打开表失败: Can’t open file: ‘×××.MYI’ (errno: 145) 。
 
Error: Table 'p' is marked as crashed and should be repaired 。

Incorrect key file for table: '...'. Try to repair it
 
Mysql表的恢复:

对于MyISAM表的恢复:

可使用Mysql自带的myisamchk工具: myisamchk -r tablename  或者 myisamchk -o tablename(比前面的更保险) 对表进行修复

五、对于count()查询来讲MyISAM更有优点

由于MyISAM存储了表中的行数记录,执行SELECT COUNT() 的时候能够直接获取到结果,而InnoDB须要扫描所有数据后获得结果。

可是注意一点:对于带有WHERE 条件的 SELECT COUNT()语句两种引擎的表执行过程是同样的,都须要扫描所有数据后获得结果

六、 InnoDB是为处理巨大数据量时的最大性能设计,它的CPU效率多是任何其它基于磁盘的关系数据库引擎所不能匹敌的。

七、MyISAM支持全文索引(FULLTEXT),InnoDB不支持

八、MyISAM引擎的表的查询、更新、插入的效率要比InnoDB高

网上截取了前辈们测试结论: 

测试方法:连续提交10个query, 表记录总数:38万 , 时间单位 s
 
        引擎类型                    MyISAM                InnoDB              性能相差
 
        count                      0.0008357            3.0163                3609
 
        查询主键                  0.005708              0.1574                27.57
 
        查询非主键                  24.01                  80.37                3.348
 
        更新主键                  0.008124            0.8183                100.7
 
        更新非主键                0.004141            0.02625              6.338
 
        插入                        0.004188            0.3694                88.21
 

    (1)加了索引之后,对于MyISAM查询能够加快:4 206.09733倍,对InnoDB查询加快510.72921倍,同时对MyISAM更新速度减慢为原来的1/2,InnoDB的更
  新速度减慢为原来的1/30。要看状况决定是否要加索引,好比不查询的log表,不要作任何的索引。
 
    (2)若是你的数据量是百万级别的,而且没有任何的事务处理,那么用MyISAM是性能最好的选择。
 
    (3)InnoDB表的大小更加的大,用MyISAM可省不少的硬盘空间。
 
        在咱们测试的这个38w的表中,表占用空间的状况以下:
            引擎类型                    MyISAM              InnoDB
            数据                      53,924 KB          58,976 KB
            索引                      13,640 KB          21,072 KB
            占用总空间              67,564 KB          80,048 KB
  
        另一个176W万记录的表, 表占用空间的状况以下:
 
            引擎类型                MyIsam              InnorDB
            数据                  56,166 KB          90,736 KB
            索引                  67,103 KB          88,848 KB
            占用总空间        123,269 KB        179,584 KB

 

7、性能对比

 

测试的版本是mysql  Ver 14.14 Distrib 5.1.49, for debian-linux-gnu (i686),使用的是Innodb plugin 1.0.8(官方称比built-in版本性能更好)和默认的MyISAM。

测试机器是笔记本,配置以下:Intel 酷睿2双核 P8600,2G*2 DDR3 1066内存,320G硬盘5400转。

测试一:数据插入性能测试,这里我分别对innodb_flush_log_at_trx_commit参数打开和关闭都测了了一下,每次测试都是运行40s,表中数字都是实际插入条数。

                       MyISAM                 Innodb (打开)      Innodb (关闭)

单线程,逐个插入         120000                 60000              60000

4线程,逐个插入          40000*4                20000*4            40000*4

单线程,批量100条/次插入  3600*100               800*100            3000*100

单线程,批量200条/次插入  1800*200               400*200            1600*200

能够发现批量插入的性能远高于单条插入,可是一次批量的大小对性能影响不大。每条记录是否都刷新日志的参数对innodb性能的影响巨大。整体上来讲,MyISAM性能更优一点。这里有一点须要注意,在插入测试过程当中,我对系统资源进行了监控,发现MyISAM对系统资源占用很低,可是Innodb对磁盘占用却很高,应该是对事务控制多了不少须要记录的日志。

测试二:数据读取性能测试。每次随机读取1000条记录,反复进行读取。

                        MyISAM        Innodb

单线程,200次读取         5.7s          16.7s

4线程,200次读取          12s           40.8s

能够看出MyISAM的读取性能很是恐怖,性能差距在3倍的样子。

以上两个测试发现MyISAM在无事务的需求下几乎完胜,可是要知道它是表锁,Innodb是行锁,那么在并发读写同时存在的状况下,那结果会是怎么样呢?!

测试三:两个线程并发写入,2个线程并发读取。

                       MyISAM                                 Innodb

逐个插入                写入40s:10000*2 读取200次*2:14s        写入40s:60000*2 读取200次*2:50s

批量100条/次插入        写入40s:1000*100*2 读取200次*2:10s      写入40s:1500*100*2 读取200次*2:50s

这下马上显示出Innodb在并发状况下强劲的性能,几乎没有什么性能衰减。而MyISAM单条插入速度变得很是慢,批量插入也降低了40%性能。

总结一下,在写多读少的应用中仍是Innodb插入性能更稳定,在并发状况下也能基本,若是是对读取速度要求比较快的应用仍是选MyISAM。

 

 

转自于:http://blog.csdn.net/wjtlht928/article/details/46641865

相关文章
相关标签/搜索