详解MySQL两种存储引擎MyISAM和InnoDB的优缺点

在《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语句显式的放在begincommit之间,作为一个事务去提交。

数据存储结构

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)是一种基于倒排索引的技术,主要用于对CHARVARCHARTEXT类型字段中的每个词(除去停用词)进行索引,以实现高效的文本搜索功能。

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。

相关推荐
半路_出家ren3 小时前
设计一个学生管理系统的数据库
linux·数据库·sql·mysql·网络安全·数据库管理员
追逐时光者3 小时前
一个基于 .NET 8 + Vue3 实现的极简 RABC 权限管理系统
后端·.net
勇闯天涯&波仔4 小时前
verilog阻塞赋值和非阻塞赋值的区别
后端·fpga开发·硬件架构·硬件工程
lang201509285 小时前
Spring Boot Actuator深度解析与实战
java·spring boot·后端
lang201509285 小时前
Spring注解配置全解析
java·后端·spring
崎岖Qiu5 小时前
【SpringAI篇01】:5分钟教会你使用SpringAI (1.0.0稳定版)
java·spring boot·后端·spring·ai
金仓拾光集5 小时前
筑牢风控生命线:金仓数据库替代MongoDB,重构证券融资融券业务的数据基石
数据库·mongodb·信创·1024程序员节·kingbasees·国产化替代
枫叶梨花5 小时前
实战:将 Nginx 日志实时解析并写入 MySQL,不再依赖 ELK
mysql·nginx·elk
那我掉的头发算什么5 小时前
【数据库】navicat的下载以及数据库约束
android·数据库·数据仓库·sql·mysql·数据库开发·数据库架构