在《MySQL的整体架构及功能详解》中我们讲解了MySQ的架构,其中包含了存储引擎层。MySQL的存储引擎层采用了插件化的设计,各存储引擎以插件形式集成到系统中。开发人员可根据应用场景选择合适的引擎(如InnoDB、MyISAM、Memory等)。
这篇文章,我们来聊聊在MySQL中比较场景的两个存储引擎:InnoDB和MyISAM。从多个维度来对比一下InnoDB和MyISAM的特性和优缺点。
什么是存储引擎
存储引擎是一种管理和存储数据的基础组件,决定了数据库系统如何处理数据的存储、索引、查询等操作。它负责数据的读写、事务管理、锁机制处理等重要功能。
数据库的存储引擎可以理解为具体实现"数据如何存和取"的模块,在数据库系统中,它是一个非常关键的部分。
在 MySQL 中,存储引擎是模块化的,不同存储引擎具备不同的特性,不同的存储引擎适合不同的场景。用户可以根据具体业务需求选择合适的存储引擎。
查看存储引擎
在MySQL中,可以通过show engines来查看支持的存储引擎。
objectivec
mysql> show engines;
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
| ndbcluster | NO | Clustered, fault-tolerant tables | NULL | NULL | NULL |
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| InnoDB | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| PERFORMANCE_SCHEMA | YES | Performance Schema | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| FEDERATED | NO | Federated MySQL storage engine | NULL | NULL | NULL |
| ndbinfo | NO | MySQL Cluster system information storage engine | NULL | NULL | NULL |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
+--------------------+---------+----------------------------------------------------------------+--------------+------+------------+
通过show engines命令执行的结果可以看到,MySQL支持了多款存储引擎,默认采用InnoDB存储引擎。并且针对不同的存储引擎,也展示它是否支持Transactions(事务)、XA(分布式事务支持)和Savepoints(保存点)等。
也可以通过如下命令查看MySQL支持的默认存储引擎:
sql
mysql> SHOW VARIABLES LIKE 'default_storage_engine';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
+------------------------+--------+
MyISAM和InnoDB简介
在MySQL5.5版本之前,采用MyISAM作为默认数据存储引擎。MyISAM存储引擎的优势是性能极佳,同时提供了功能特性,比如全文索引、压缩、空间函数等。
但MyISAM的缺点也很明显,它不支持事务和行级锁,而且在异常情况下((例如断电或系统崩溃时)无法安全恢复数据。
在MySQL5.5版本之后,MySQL引入了InnoDB作为默认数据存储引擎,取代了之前的默认存储引擎 MyISAM。相较于ISAM和MyISAM,InnoDB最大的特色就是支持了ACID兼容的事务功能。
从具体场景角度来说,现代的应用系统对数据库事务(ACID 特性)的需求也是越来越高。这也是为什么大家大多数情况下都选择InnoDB存储引擎的原因。当然,在某些情况下,MyISAM的表现会更好。
比较与分析
下面,我们通过常见的几个维度来对比一下InnoDB和MyISAM两款存储引擎的差异。
事务支持
MyISAM不支持事务,InnoDB支持事务。
InnoDB有完善的锁、事务控制机制等功能。在执行大量的INSERT、UPDATE操作时,InnoDB可以保证数据的一致性和完整性,可以提高多用户并发操作的性能。
InnoDB默认开启自动提交(AUTOCOMMIT),即每条SQL语句会默认被封装成一个事务,自动提交。通常情况下,为了提升效率,减少数据库多次提交的开销,可以将多条SQL语句在一个事务中提交,即将多条SQL语句显式的放在begin和commit之间,作为一个事务去提交。
数据存储结构
MyISAM在磁盘上会存储三个文件:
- 表定义文件(
.frm):文件类型为.frm,如:my_table.frm。该文件存储表结构的定义信息,例如列名、列类型、索引信息等。用于描述表的元数据,用来定义整个表的结构。所有存储引擎(包括 MyISAM、InnoDB 等)都使用.frm文件,共用它来存储表的元信息。通过SHOW CREATE TABLE命令查看表的创建语句,实际就是基于.frm文件内容展示。需要注意的是,该文件在MySQL 8.0中被移除,其功能由SDI文件替代。 - 数据文件(
.MYD):文件类型为.MYD,即MYData,该文件存储了表中的具体数据(即用户插入的记录)。每个表都有专属的.MYD文件,路径通常是在数据目录下/var/lib/mysql/数据库名/表名.MYD。 - 索引文件(
.MYI):文件类型为.MYI,即MYIndex,该文件存储表的索引信息,包括主键索引、普通索引等,以及必要的数据指针。用于加速表中的查询操作,是表的索引实现。每个表都有专属的.MYI文件,路径通常是在数据目录下/var/lib/mysql/数据库名/表名.MYI。 - SDI文件:在MySQL 8.0 中,MyISAM 表引入了一种新的文件类型------SDI 文件(文件后缀为
.sdi),它是用于存储表的元数据的文件。SDI 文件的全称是 Serialized Dictionary Information (序列化字典信息)。这是 MySQL 8.0 在移除.frm文件后,引入的新机制,用于保存表定义信息。SDI 文件中的内容是表数据字典的序列化形式,适用于不使用 InnoDB(如 MyISAM)的存储引擎。
InnoDB在磁盘上主要有两个文件构成:
- 表定义文件(
.frm):该文件的基本功能与MyISAM的对应文件的功能相似。同样的,该文件在MySQL 8.0中也被移除。原来存放于数据字典文件中的信息,全部存放到数据库系统表中,不再通过文件的方式存储数据字典信息。 - 数据+索引文件(
.ibd):InnoDB存储引擎特有的文件,用于存储表的数据、索引、Undo日志等内容。它是表的核心存储文件,每张表有一个对应的.ibd文件(前提是开启innodb_file_per_table),支持事务、行级锁、聚簇索引等高级功能。此外,.ibd文件在 MySQL 8.0 中配合数据字典架构,进一步优化性能,同时支持压缩和加密功能以增强数据安全性。
锁支持
MyISAM只支持表级锁,即在对数据进行操作时,会对整张表进行锁定。这种加锁方式效率较低,但在执行大量以SELECT为主的查询操作时,由于支持无锁读取,MyISAM的性能相对较好。
InnoDB则支持更细粒度的锁,即行级锁。这种锁仅对表中的某一行数据进行锁定,在执行数据修改操作(例如UPDATE和DELETE)时,使用行级锁能够有效减少锁定范围,进而降低锁定时间,提高并发性能。
在实际业务场景中,绝大多数系统都是读写混合型的(通常读多写少)。随着数据量和并发量的增加,对数据库性能的要求也越来越高。在此情况下,优先选择InnoDB会更适合,因为它既支持事务,又能在高并发场景下通过行级锁带来更好的性能表现。
表主键与外键
MyISAM允许表中不存在主键或任何索引,表中的索引仅保存对应行的物理地址。如果定义了主键,主键会作为主键索引。但相比之下,MyISAM对主键的设计较为简单。
InnoDB则要求每个表必须有主键。如果用户未显式定义主键或非空唯一索引,InnoDB会自动生成一个不可见的6字节主键。InnoDB存储数据时,将以主键索引为数据的组织方式(即数据是按主键顺序存储的),而二级索引用主键值来定位行数据。这种设计使InnoDB的主键范围更大,其上限是MyISAM的两倍。
MyISAM不支持外键概念,因此无法实现表与表之间的约束关系管理。
InnoDB支持外键约束,能够使表的关系更加清晰,确保数据完整性和一致性。然而,外键也存在两面性。虽然它可以减少应用层的约束逻辑设计,但在高并发场景中容易成为性能瓶颈,尤其是在分布式架构中,外键的使用通常并不推荐,因为它可能影响数据库的扩展性和性能优化。
全文索引
全文索引(FULLTEXT)是一种基于倒排索引的技术,主要用于对CHAR、VARCHAR和TEXT类型字段中的每个词(除去停用词)进行索引,以实现高效的文本搜索功能。
MyISAM原生支持FULLTEXT类型的全文索引,在处理文本搜索时表现较为优秀。然而,MyISAM的全文索引存在局限性,例如它不支持中文分词。
对于中文搜索,用户必须在插入数据前自行分词,并用空格分隔后存入表中。此外,对于小于4个汉字的词,MyISAM会将其视为停用词,也会被忽略。
在MySQL 5.6之前,InnoDB并不支持全文索引功能。如果需要全文检索,通常需要借助外部工具,例如Sphinx或其他专业的全文搜索引擎。从MySQL 5.6开始,InnoDB开始支持FULLTEXT索引,但其性能和功能仍然限制较多。
尽管MySQL(包括MyISAM和InnoDB)提供了全文索引功能,但实际上全文检索并不是MySQL的强项,尤其在数据量大、并发高的场景下,自带的全文索引容易造成数据库资源和内存的高消耗,进而影响整体性能。
因此,对于专业的全文检索需求,推荐使用现代的搜索引擎或组件,例如 Elasticsearch(ES)或 Sphinx,这些工具在处理全文检索方面性能更强、功能更丰富。
数据计量:COUNT(*)
MyISAM的COUNT(*)处理方式:
MyISAM存储引擎会直接利用内部数据结构保存的表行数来快速返回COUNT(*)的结果,而无需扫描整张表。这使得MyISAM在执行COUNT(*)操作时非常高效,尤其是在没有WHERE条件的情况下。
但需要注意,MyISAM不支持事务或行级锁,因此在高并发场景下,数据一致性问题可能会导致统计结果不是完全准确。
当COUNT(*)查询包含WHERE条件时,MyISAM会依赖索引和行扫描来计算满足条件的行数,从而性能可能受到影响。
InnoDB的COUNT(*)处理方式:
与MyISAM不同,InnoDB在执行COUNT(*)时无法直接获取表的行数。这是因为InnoDB需要通过行扫描或索引扫描来计算行数,同时它会使用统计信息来优化查询性能。
如果查询包含WHERE条件,InnoDB会使用索引来加速过滤满足条件的行,但对于未加条件的COUNT(*),性能通常会比MyISAM稍逊。
需要注意,InnoDB的统计信息是估算性的,在某些情况下可能不完全准确。
带条件查询的行为:
当COUNT(*)查询包含WHERE条件时,无论是MyISAM还是InnoDB,都会根据查询条件进行行扫描或索引扫描来计算符合条件的行数。两种存储引擎处理方式基本类似,只是性能表现可能因特定场景有所不同。
优化建议:
为了提高COUNT(*)的查询效率,无论选择MyISAM还是InnoDB存储引擎,建议为查询涉及的字段建立合理的索引,同时在查询中尽量使用过滤条件来减少扫描范围。例如:
sql
SELECT COUNT(*) FROM tb_userinfo WHERE sex = 0 AND age > 22;
通过WHERE条件过滤数据并合理设计索引,可以有效提升性能。
小结
这篇文章只是列举了InnoDB和MyISAM主要方面的功能与特性的对比,在实践的过程中,可以根据具体的业务场景来选择适合的存储引擎。
比如,如果需要执行大量的查询语句,且不需要事务支持,则可考虑MyISAM。如果需要执行大量的INSERT或UPDATE操作,且需要事务支持、行级锁和外键支持,那么可考虑InnoDB。在目前的互联网场景下,通常建议选择InnoDB。