一、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