MySQL中 InnoDB 和 MyISAM 小结

InnoDB和MyISAM是许多人在使用MySQL时最经常使用的两个表类型,这两个表类型各有优劣,视具体应用而定。基本的差异为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,可是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。 如下是一些细节和具体实现的差异:html

  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特性(例如外键)的表不适用。
  6. InnoDB表的行锁也不是绝对的,假如在执行一个SQL语句时mysql不能肯定要扫描的范围,InnoDB表一样会锁全表,例如update table set num=1 where name like “%aaa%”   两种类型最主要的差异就是Innodb 支持事务处理与外键和行级锁.而MyISAM不支持.因此MyISAM每每就容易被人认为只适合在小项目中使用。   我做为使用MySQL的用户角度出发,Innodb和MyISAM都是比较喜欢的,可是从我目前运维的数据库平台要达到需求:99.9%的稳定性,方便的扩展性和高可用性来讲的话,MyISAM绝对是个人首选。

缘由以下:   一、首先我目前平台上承载的大部分项目是读多写少的项目,而MyISAM的读性能是比Innodb强很多的。   二、MyISAM的索引和数据是分开的,而且索引是有压缩的,内存使用率就对应提升了很多。能加载更多索引,而Innodb是索引和数据是紧密捆绑的,没有使用压缩从而会形成Innodb比MyISAM体积庞大不小。   三、从平台角度来讲,常常隔1,2个月就会发生应用开发人员不当心update一个表where写的范围不对,致使这个表无法正经常使用了,这个时候MyISAM的优越性就体现出来了,随便从当天拷贝的压缩包取出对应表的文件,随便放到一个数据库目录下,而后dump成sql再导回到主库,并把对应的binlog补上。若是是Innodb,恐怕不可能有这么快速度,别和我说让Innodb按期用导出xxx.sql机制备份,由于我平台上最小的一个数据库实例的数据量基本都是几十G大小。   四、从我接触的应用逻辑来讲,select count() 和order by 是最频繁的,大概能占了整个sql总语句的60%以上的操做,而这种操做Innodb其实也是会锁表的,不少人觉得Innodb是行级锁,那个只是where对它主键是有效,非主键的都会锁全表的。   五、还有就是常常有不少应用部门须要我给他们按期某些表的数据,MyISAM的话很方便,只要发给他们对应那表的frm.MYD,MYI的文件,让他们本身在对应版本的数据库启动就行,而Innodb就须要导出xxx.sql了,由于光给别人文件,受字典数据文件的影响,对方是没法使用的。   六、若是和MyISAM比insert写操做的话,Innodb还达不到MyISAM的写性能,若是是针对基于索引的update操做,虽然MyISAM可能会逊色Innodb,可是那么高并发的写,从库可否追的上也是一个问题,还不如经过多实例分库分表架构来解决。   七、若是是用MyISAM的话,merge引擎能够大大加快应用部门的开发速度,他们只要对这个merge表作一些select count()操做,很是适合大项目总量约几亿的rows某一类型(如日志,调查统计)的业务表。   固然Innodb也不是绝对不用,用事务的项目如模拟炒股项目,我就是用Innodb的,活跃用户20多万时候,也是很轻松应付了,所以我我的也是很喜欢Innodb的,只是若是从数据库平台应用出发,我仍是会首选MyISAM。   另外,可能有人会说你MyISAM没法抗太多写操做,可是我能够经过架构来弥补,说个我现有用的数据库平台容量:主从数据总量在几百T以上,天天十多亿 pv的动态页面,还有几个大项目是经过数据接口方式调用未算进pv总数,(其中包括一个大项目由于初期memcached没部署,致使单台数据库天天处理 9千万的查询)。而个人总体数据库服务器平均负载都在0.5-1左右。java

MyISAMmysql

InnoDB
复制代码

构成上的区别:算法

每一个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。
复制代码

.frm文件存储表定义。sql

数据文件的扩展名为.MYD (MYData)。数据库

索引文件的扩展名是.MYI (MYIndex)。缓存

基于磁盘的资源是InnoDB表空间数据文件和它的日志文件,InnoDB 表的大小只受限于操做系统文件的大小,通常为 2GB
复制代码

事务处理上方面:安全

MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,可是不提供事务支持

  InnoDB提供事务支持事务,外部键等高级数据库功能
复制代码

SELECT UPDATE,INSERT,Delete操做 若是执行大量的SELECT,MyISAM是更好的选择服务器

1.若是你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表
复制代码

2.DELETE FROM table时,InnoDB不会从新创建表,而是一行一行的删除。架构

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

对AUTO_INCREMENT的操做

每表一个AUTO_INCREMEN列的内部处理。
复制代码

MyISAM为INSERT和UPDATE操做自动更新这一列。这使得AUTO_INCREMENT列更快(至少10%)。在序列顶的值被删除以后就不能再利用。(当AUTO_INCREMENT列被定义为多列索引的最后一列,能够出现重使用从序列顶部删除的值的状况)。

AUTO_INCREMENT值可用ALTER TABLE或myisamch来重置

对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,可是在MyISAM表中,能够和其余字段一块儿创建联合索引

更好和更快的auto_increment处理

若是你为一个表指定AUTO_INCREMENT列,在数据词典里的InnoDB表句柄包含一个名为自动增加计数器的计数器,它被用在为该列赋新值。
复制代码

自动增加计数器仅被存储在主内存中,而不是存在磁盘上

关于该计算器的算法实现,请参考

AUTO_INCREMENT列在InnoDB里如何工做

表的具体行数 select count() from table,MyISAM只要简单的读出保存好的行数,注意的是,当count()语句包含 where条件时,两种表的操做是同样的

InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行
复制代码

锁 表锁

提供行锁(locking on row level),提供与 Oracle 类型一致的不加锁读取(non-locking read in
复制代码

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

InnoDB 和 MyISAM,是在使用MySQL最经常使用的两个表类型,各有优缺点,视具体应用而定。下面是已知的二者之间的差异,仅供参考。

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 上第一个提供外键约束(FOREIGNKEY constraints)的表引擎。 InnoDB 的设计目标是处理大容量数据库系统,它的 CPU 利用率是其它基于磁盘的关系数据库引擎所不能比的。在技术上,InnoDB 是一套放在 MySQL 后台的完整数据库系统,InnoDB 在主内存中创建其专用的缓冲池用于高速缓冲数据和索引。 InnoDB 把数据和索引存放在表空间里,可能包含多个文件,这与其它的不同,举例来讲,在 MyISAM 中,表被存放在单独的文件中。InnoDB 表的大小只受限于操做系统的文件大小,通常为 2 GB。 在 http://www.innodb.com/ 上能够找到 InnoDB 最新的信息。InnoDB 手册的最新版本老是被放置在那里,而且在那里能够获得 InnoDB 的商业许可(order commercial licenses)以及支持。 InnoDB 如今(2001年十月)在一些大的需高性能的数据库站点上被使用。著名的 Internet 新闻站点 Slashdot.org就是使用的 InnoDB。 Mytrix, Inc. 在 InnoDB 表上存储了超过 1 TB 的数据,并且另外的一个站点在 InnoDB 表上处理着平均每秒 800 次的插入/更新的负载。

MyISAM MyISAM 是MySQL缺省存贮引擎 . 每张MyISAM 表被存放在盘在三个文件 frm 文件存放表格定义 数据文件是MYD (MYData) 索引文件是MYI (MYIndex) 引申 如下是一些细节和具体实现的差异: 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的性能优点。 MyIASM是IASM表的新版本,有以下扩展: 1. NULL列索引。
2. 对变长行比ISAM表有更少的碎片。
3. 支持大文件。
4. 更好的索引压缩。
5. 更好的键码统计分布。
6. 更好和更快的auto_increment处理。 7. 二进制层次的可移植性。 转载声明:本文转自(http://www.diybl.com/course/7_databases/mysql/Mysqljs/2008924/145307.html)

MySQL InnoDB 的性能问题讨论

MySQL最为人垢病的缺点就是缺少事务的支持,MyISAM 性能虽然出众,不是没有代价的,InnoDB 又如何呢?InnoDB 的磁盘性能很使人担忧,MySQL 缺少良好的 tablespace 真是天大的缺陷!

InnoDB的表空间分红三种,一种是裸设备,一种是若干个 ibdata 文件(缺省方式),再一种是 Per-Table 文件,第一种用得少,第二种显然比第三种效率更差,本文的讨论基于 Per-Table,也即 innodb_file_per_table 配置参数。

现象重现:导出一个几百万行数据、带若干索引、有过频繁更新的表出来再导入,若是能以真实环境下的表来作测试就更理想,到 data 目录下观察对应的数据文件的 size 增加状况,会发现前 1G 速度至关使人满意,但是越日后效率越低,到后面基本就是蜗牛般的速度了。

不是只有导入才会让你慢得受不了,alter column/index 都会这样。。。

InnoDB 跟磁盘相关的文件存储,能够分红两个部分,一个是日志文件,另外一个是数据文件。当有频繁的 INSERT/UPDATE 操做的时候,InnoDB 须要分别写入这两个文件,日志文件是顺序操做,数据文件包括了表数据和索引数据两个部分(和 MyISAM 直接拆开成表文件和索引文件不一样,InnoDB 的表和索引是在同一个文件当中的)。

InnoDB 的索引用的是 BTREE 格式,若是当前更新的记录影响到索引的变化,逻辑上就存在三个操做,从原来的 BTREE 找到并摘除原来这行的记录并作调整、插入行数据、根据新数据查找 BTREE 相应的位置并从新插入新索引信息,假设索引数为 N,相应的逻辑操做数就为 1 + 2N,显然这些信息不能保证在同一个磁盘连续空间上,所以须要 1 + 2N 次的磁头移动,行数越大、文件尺寸越大,磁头的移动幅度也就可能越大,带来的后果显然是极差的磁盘 IO 效率。

MySQL 对于 MyISAM 的的磁盘 IO 优化是如何建议的呢?使用符号连接将表文件和索引文件分别指向不一样的不一样的目录,分散到不一样的磁盘上以增长系统的访问速度。这种优化方式,在 InnoDB 上彻底没有可能性!

若是有 tablespace 支持,磁盘效率问题就好解决了,一如商业数据库的作法,将日志、表文件、索引文件分别分布到不一样的表空间也就是物理磁盘上,但是 MySQL 一直到 5.1 都没有提供 tablespace 功能,仅在 NDB/NDBCLUSTER 中才提供,可是 -- "CREATE TABLESPACE was added in MySQL 5.1.6. In MySQL 5.1, it is useful only with Disk Data storage for MySQL Cluster."。

不知道 Yahoo 等大网站是怎么解决这个难题的。。。头痛。。。考虑切换到 PostgreSQL 中。。。

转载声明:本文转自http://www.javaeye.com/topic/34676

MySQL提供了数据库的同步功能,这对咱们实现数据库的冗灾、备份、恢复、负载均衡等都是有极大帮助的。本文描述了常见的同步设置方法。 1、准备服务器 因为MySQL不一样版本之间的(二进制日志)binlog格式可能会不同,所以最好的搭配组合是Master的MySQL版本和Slave的版本相同或者更低,Master的版本确定不能高于Slave版本。 本文中,咱们假设主服务器(如下简称Master)和从服务器(如下简称Slave)的版本都是5.0.15,操做系统是Linux Ubuntu 5.0.x。 假设同步Master的主机名为:rep1,Slave主机名为:rep2,2个MySQL的basedir目录都是/usr/local/mysql,datadir都是:/usr/local/MySQL/data。 2、设置同步服务器 一、设置同步Master 每一个同步服务器都必须设定一个惟一的编号,不然同步就不能正常运行了。接下来开始修改 my.cnf,增长如下几行: server-id = 1 log-bin set-variable=binlog-ignore-db=MySQL 而后在Master上增长一个帐号专门用于同步,以下: MySQL>GRANT REPLICATION SLAVE ON . TO rep@rep2 IDENTIFIED BY 'rep'; 若是想要在Slave上有权限执行 "LOAD TABLE FROM MASTER" 或 "LOAD DATA FROM MASTER" 语句的话,必须授予全局的 FILE 和 SELECT 权限: MySQL>GRANT FILE,SELECT,REPLICATION SLAVE ON . TO rep@rep2 IDENTIFIED BY 'rep'; 第三行表示不记录数据库MySQL的更新日志,这就避免了Master上的权限设置等被同步到Slave上,若是对这方面没有限制,就能够不设置这个参数。 接下来备份Master上的数据,首先执行以下SQL语句: MySQL>FLUSH TABLES WITH READ LOCK; 不要退出这个终端,不然这个锁就不生效了;接着导出数据,能够直接打包压缩数据文件,也可使用MySQLdump工具来作,推荐前者的方法,这样更为快捷简便。 root$cd /usr/local/MySQL root$tar zcf data.tar.gz ./data (在这里也多是 "var" 等其它实际存放数据文件的目录,根据实情而定) 而后将这些数据拷贝到Slave服务器上,解开,设置好正确的权限及属主等;以后,执行 "UNLOCK TABLES" 语句来释放锁。 二、设置Slave 修改my.cnf,增长以下几行: server-id = 2 master-host = rep1 #主服务器名 master-user = rep #同步帐户名,默认是test master-password = rep #同步账户密码,默认是空 master-port = 3306 #主服务器的 TCP/IP 端口号,默认是3306 set-variable=replicate-ignore-db=MySQL #略过同步的数据库名,若是有多个,请设置屡次 set-variable=replicate-do-db=yejr #想要同步的数据库名,若是有多个,请设置屡次 接下来在Slave上检验一下是否能正确链接到Master上,而且具有相应的权限。 root$MySQL -hrep1 -urep -prep MySQL>SHOW GRANTS; +---------------------------------------------------------------------------------------------------------------------+ | Grants for rep@rep2 | +---------------------------------------------------------------------------------------------------------------------+ | GRANT SELECT, FILE, REPLICATION SLAVE ON . TO 'rep'@'rep2' IDENTIFIED BY PASSWORD '*9FF2C222F44C7BBA5CC7E3BE8573AA4E1776278C' | +---------------------------------------------------------------------------------------------------------------------+ 如今,能够启动Slave了。启动成功后,登陆Slave,查看一下同步状态: MySQL -hlocalhost -uroot MySQL>SHOW SLAVE STATUS/G *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: rep1 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: binlog.000001 Read_Master_Log_Pos: 98 Relay_Log_File: relay.000003 Relay_Log_Pos: 232 Relay_Master_Log_File: binlog.000001 Slave_IO_Running: Yes Slave_SQL_Running: Yes Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 0 Last_Error: Skip_Counter: 0 Exec_Master_Log_Pos: 98 Relay_Log_Space: 232 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: 0 1 row in set (0.00 sec) 能够看到,Slave_IO_Running 和 Slave_SQL_Running 两列的值都为 "Yes",这代表 Slave 的 I/O 和 SQL 线程都在正常运行。

MySQL服务器安装完以后如何调节性能 key_buffer_size - 这对MyISAM表来讲很是重要。若是只是使用MyISAM表,能够把它设置为可用内存的 30-40%。合理的值取决于索引大小、数据量以及负载 -- 记住,MyISAM表会使用操做系统的缓存来缓存数据,所以须要留出部份内存给它们,不少状况下数据比索引大多了。尽管如此,须要老是检查是否全部的 key_buffer 都被利用了 -- .MYI 文件只有 1GB,而 key_buffer 却设置为 4GB 的状况是很是少的。这么作太浪费了。若是你不多使用MyISAM表,那么也保留低于 16-32MB 的 key_buffer_size 以适应给予磁盘的临时表索引所需。

innodb_buffer_pool_size - 这对Innodb表来讲很是重要。Innodb相比MyISAM表对缓冲更为敏感。MyISAM能够在默认的 key_buffer_size 设置下运行的能够,然而Innodb在默认的 innodb_buffer_pool_size 设置下却跟蜗牛似的。因为Innodb把数据和索引都缓存起来,无需留给操做系统太多的内存,所以若是只须要用Innodb的话则能够设置它高达 70-80% 的可用内存。一些应用于 key_buffer 的规则有 -- 若是你的数据量不大,而且不会暴增,那么无需把 innodb_buffer_pool_size 设置的太大了。

innodb_additional_pool_size - 这个选项对性能影响并不太多,至少在有差很少足够内存可分配的操做系统上是这样。不过若是你仍然想设置为 20MB(或者更大),所以就须要看一下Innodb其余须要分配的内存有多少。

innodb_log_file_size 在高写入负载尤为是大数据集的状况下很重要。这个值越大则性能相对越高,可是要注意到可能会增长恢复时间。我常常设置为 64-512MB,跟据服务器大小而异。

innodb_log_buffer_size 默认的设置在中等强度写入负载以及较短事务的状况下,服务器性能还能够。若是存在更新操做峰值或者负载较大,就应该考虑加大它的值了。若是它的值设置过高了,可能会浪费内存 -- 它每秒都会刷新一次,所以无需设置超过1秒所需的内存空间。一般 8-16MB 就足够了。越小的系统它的值越小。

innodb_flush_logs_at_trx_commit 是否为Innodb比MyISAM慢1000倍而头大?看来也许你忘了修改这个参数了。默认值是 1,这意味着每次提交的更新事务(或者每一个事务以外的语句)都会刷新到磁盘中,而这至关耗费资源,尤为是没有电池备用缓存时。不少应用程序,尤为是从 MyISAM转变过来的那些,把它的值设置为 2 就能够了,也就是不把日志刷新到磁盘上,而只刷新到操做系统的缓存上。日志仍然会每秒刷新到磁盘中去,所以一般不会丢失每秒1-2次更新的消耗。若是设置为 0 就快不少了,不过也相对不安全了 -- MySQL服务器崩溃时就会丢失一些事务。设置为 2 指挥丢失刷新到操做系统缓存的那部分事务。

table_cache -- 打开一个表的开销可能很大。例如MyISAM把MYI文件头标志该表正在使用中。你确定不但愿这种操做太频繁,因此一般要加大缓存数量,使得足以最大限度地缓存打开的表。它须要用到操做系统的资源以及内存,对当前的硬件配置来讲固然不是什么问题了。若是你有200多个表的话,那么设置为 1024 也许比较合适(每一个线程都须要打开表),若是链接数比较大那么就加大它的值。我曾经见过设置为 100,000 的状况。

thread_cache -- 线程的建立和销毁的开销可能很大,由于每一个线程的链接/断开都须要。我一般至少设置为 16。若是应用程序中有大量的跳跃并发链接而且 Threads_Created 的值也比较大,那么我就会加大它的值。它的目的是在一般的操做中无需建立新线程。

query_cache -- 若是你的应用程序有大量读,并且没有应用程序级别的缓存,那么这颇有用。不要把它设置太大了,由于想要维护它也须要很多开销,这会致使MySQL变慢。一般设置为 32-512Mb。设置完以后最好是跟踪一段时间,查看是否运行良好。在必定的负载压力下,若是缓存命中率过低了,就启用它。

注意:就像你看到的上面这些全局表量,它们都是依据硬件配置以及不一样的存储引擎而不一样,可是会话变量一般是根据不一样的负载来设定的。若是你只有一些简单的查询,那么就无需增长 sort_buffer_size 的值了,尽管你有 64GB 的内存。搞很差也许会下降性能。 我一般在分析系统负载后才来设置会话变量。

查看引擎类型 通常状况下,MySQL会默认提供多种存储引擎,能够经过下面的查看:

(1)看你的MySQL如今已提供什么存储引擎: mysql> show engines;

(2)看你的MySQL当前默认的存储引擎: mysql> show variables like '%storage_engine%';

(3)你要看某个表用了什么引擎(在显示结果里参数engine后面的就表示该表当前用的存储引擎): mysql> show create table 表名;

(4) 查看引擎状态: show engine innodb status;

相关文章
相关标签/搜索