关于 MyISAM 引擎你可能不知道的三件事

[TOC]

存在即合理,虽然在互联网公司中 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 "%datadir%"; 可以查看数据库文件位置。

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 函数。

关于前缀索引,松哥之前已经专门写过文章介绍过了:

2.4 表压缩

MyISAM 表支持数据压缩。

对于一些很大的只读表,我们可以对其进行压缩,这样可以有效节省磁盘 IO。MyISAM 表在压缩的时候是对单行数据进行压缩的,所以我们并不用担心在读取一行数据的时候会对表进行解压。

MyISAM 表压缩的命令是 myisampack,我们来看一个简单案例:

首先进入到数据库文件目录中查看当前的数据库文件:

然后我们对 user.MYI 文件进行强制压缩:

user.OLD 是压缩之前的文件备份,其他的是压缩后的文件,由于松哥这里的样例数据比较少,所以压缩之后的效果不是很明显(压缩后的文件反而变大了,如果数据量比较大,就不会出现这个问题)。

压缩完成后,我们再对数据表进行操作,如下:

可以看到,只有查询操作是 OK 的,其他的增删改都是不可以的,因为压缩后的 user 表就是一个只读表。

2.5 单表限制

在 MySQL5.0 之前,使用 MyISAM 引擎的数据表,单表最大大小为 4G,如果我们存储的数据超过了 4G,就需要在创建表的时候,手动调整可存储的数据行数以及每行的数据大小。

创建表时我们可以通过如下方式修改这两个变量:

1
2
3
4
CREATE TABLE user2 (
id INTEGER NOT NULL PRIMARY KEY,
name CHAR(18) NOT NULL
) MAX_ROWS = 1000000000 AVG_ROW_LENGTH = 32;

对于已存在的表,我们可以通过如下方法修改这两个变量:

1
ALTER TABLE user2 MAX_ROWS=1000000000 AVG_ROW_LENGTH=15000;

当然,这都是老黄历了!

在 MySQL5.0 之后,单表的大小限制变成了 256TB,这基本上够用了。

3.使用场景

  • 非事务型应用(MyISAM 不支持事务)
  • 只读数据(可在表压缩之后使用)

4.小结

好啦,几天就先和小伙伴们扯这么多~

参考资料:

  1. https://zhuanlan.zhihu.com/p/123962424
  2. https://www.cnblogs.com/studyzy/p/4310653.html
# MySQL

喜欢这篇文章吗?扫码关注公众号【江南一点雨】【江南一点雨】专注于 SPRING BOOT+微服务以及前后端分离技术,每天推送原创技术干货,关注后回复 JAVA,领取松哥为你精心准备的 JAVA 干货!

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×