松哥原创的 Spring Boot 视频教程已经杀青,感兴趣的小伙伴戳这里-->Spring Boot Vue 微人事视频教程
存在即合理,虽然在互联网公司中 InnoDB 引擎使用较多,但是 MyISAM 引擎的特性自有它自己的使用场景,今天松哥就来和大家捋一捋 MyISAM,这也是我们 MySQL 进阶必经之路。
1.MyISAM
MyISAM 是 MySQL 的默认数据库引擎(5.5版之前),由早期的 ISAM 所改良。虽然性能极佳,但却有一个缺点:不支持事务处理(transaction)。最近几年,MySQL 逐渐使用 InnoDB 代替了 MyISAM,关于 InnoDB 和 MyISAM 的历史纠葛,松哥在上篇文章中(MySQL 体系架构简介)已经和大家介绍过了,这里就不再赘述。
每一个使用 MyISAM 存储引擎的数据表,数据都会存放在两个文件中 .MYD
和 .MYI
,例如我新建一个使用了 MyISAM 存储引擎的表,名为 user,然后我们找到 user 表的存放位置,可以看到如下三个文件:
- user.frm:存储表结构信息,这个和 MyISAM 引擎没有关系。
- user.MYD:存放表数据。
- user.MYI:存放索引信息。
题外话,如何查看数据库文件位置?
❝执行命令
show global variables like "�tadir%";
可以查看数据库文件位置。
2.特性
那么 MyISAM 都有哪些特性呢?接下来我们就从如下几个方面来介绍下。
2.1 锁级别
基本上大家看到所有讲 MyISAM 和 InnoDB 区别的资料,都会提到这一点,因为这是它俩最为重要的区别,MyISAM 是表级锁(table-level locking),而 InnoDB 支持行级锁(row-level locking),也支持表级锁,但是默认情况下是行级锁。
- 表级锁的特点是开销小,加锁快,不会出现死锁,但是锁定粒度较大,发生锁冲突的概率高,而且并发度也低。
- 行级锁的特点是开销大,加锁慢,有可能会出现死锁,但是它的锁定粒度小,发生锁冲突的概率低,并发度也高。
根据锁的特点来看,表级锁更适合于查询操作(读写混合操作执行效率较低),而行级锁则更适合并发更新、并发查询的应用,因为我们今天的主角是 MyISAM,所以我们这里就先不讨论行级锁的问题,表级锁松哥在上篇文章中也已经介绍过了,这里就不再赘述。没看上篇的小伙伴可以参考:MySQL 中的表级锁很差劲吗?。
2.2 check/repair
可以通过 check table 命令来查看 MyISAM 表是否损坏,也可以通过 repair table 命令来修复一个被损坏的 MyISAM 表。
2.3 全文索引
MyISAM 支持全文索引,曾经这是它非常重要的一个特性。因为从 MySQL5.6 开始,InnoDB 才支持全文索引,在这之前,官方的存储引擎只有 MyISAM 支持全文索引。
另外需要注意的是,MyISAM 引擎还可以建立前缀索引(InnoDB 也支持),所谓前缀索引说白了就是对文本的前几个字符(具体是几个字符在建立索引时指定)建立索引,这样建立起来的索引更小,所以查询更快。这有点类似于 Oracle 中对字段使用 Left 函数来建立函数索引,只不过 MySQL 的这个前缀索引在查询时是内部自动完成匹配的,并不需要使用 Left 函数。
关于前缀索引,松哥之前已经专门写过文章介绍过了:
- 这个 MySQL 索引选择性有点意思!
2.4 表压缩
MyISAM 表支持数据压缩。
对于一些很大的只读表,我们可以对其进行压缩,这样可以有效节省磁盘 IO。MyISAM 表在压缩的时候是对单行数据进行压缩的,所以我们并不用担心在读取一行数据的时候会对表进行解压。
MyISAM 表压缩的命令是 myisampack,我们来看一个简单案例:
首先进入到数据库文件目录中查看当前的数据库文件:
然后我们对 user.MYI 文件进行强制压缩:
user.OLD 是压缩之前的文件备份,其他的是压缩后的文件,由于松哥这里的样例数据比较少,所以压缩之后的效果不是很明显(压缩后的文件反而变大了,如果数据量比较大,就不会出现这个问题)。
压缩完成后,我们再对数据表进行操作,如下:
可以看到,只有查询操作是 OK 的,其他的增删改都是不可以的,因为压缩后的 user 表就是一个只读表。
2.5 单表限制
在 MySQL5.0 之前,使用 MyISAM 引擎的数据表,单表最大大小为 4G,如果我们存储的数据超过了 4G,就需要在创建表的时候,手动调整可存储的数据行数以及每行的数据大小。
创建表时我们可以通过如下方式修改这两个变量:
代码语言:javascript复制CREATE TABLE user2 (
id INTEGER NOT NULL PRIMARY KEY,
name CHAR(18) NOT NULL
) MAX_ROWS = 1000000000 AVG_ROW_LENGTH = 32;
对于已存在的表,我们可以通过如下方法修改这两个变量:
代码语言:javascript复制ALTER TABLE user2 MAX_ROWS=1000000000 AVG_ROW_LENGTH=15000;
当然,这都是老黄历了!
在 MySQL5.0 之后,单表的大小限制变成了 256TB,这基本上够用了。
3.使用场景
- 非事务型应用(MyISAM 不支持事务)
- 只读数据(可在表压缩之后使用)
4.小结
好啦,几天就先和小伙伴们扯这么多~
参考资料:
- https://zhuanlan.zhihu.com/p/123962424
- https://www.cnblogs.com/studyzy/p/4310653.html