MySQL的存储引擎之MyISAM

摘要:MySQL的存储引擎之MyISAM

MyISAM不支持事务、也不支持外键,其优势是访问速度快。对事务完整性没有要求或以SELECT、INSERT为主的应用可以考虑使用这个引擎。
每个使用MyISAM引擎的表在磁盘上都存储成3个文件,文件名都和表名相同,扩展名分别是:

  • .frm,存储表定义
  • .MYD,存储数据
  • .MYI,存储索引
root@database-one 09:03:  [gftest]> create table testmyisam(id int,name varchar(10),primary key(id)) engine=myisam;
Query OK, 0 rows affected (0.01 sec)

root@database-one 09:03:  [gftest]> exit
Bye
[root@database-one ~]# cd /home/mysql/gftest/
[root@database-one gftest]# ls -l testmyisam.*
-rw-r----- 1 mysql mysql 8586 2月  29 09:03 testmyisam.frm
-rw-r----- 1 mysql mysql    0 2月  29 09:03 testmyisam.MYD
-rw-r----- 1 mysql mysql 1024 2月  29 09:03 testmyisam.MYI
[root@database-one gftest]# 

 

数据文件和索引文件可以放在不同的目录,分散I/O,获得更好的性能,创建表时通过DATA DIRECTORY和INDEX DIRECTORY指定。

root@database-one 09:14:  [gftest]> create table testmyisam1(id int,name varchar(10),primary key(id)) engine=myisam data directory='/tmp' index directory='/tmp';
Query OK, 0 rows affected (0.20 sec)

root@database-one 09:14:  [gftest]> exit
Bye
[root@database-one gftest]# cd /tmp
[root@database-one tmp]# ls -l testmyisam*
-rw-r----- 1 mysql mysql    0 2月  29 09:14 testmyisam1.MYD
-rw-r----- 1 mysql mysql 1024 2月  29 09:14 testmyisam1.MYI
[root@database-one tmp]# cd /home/mysql/gftest/
[root@database-one gftest]# ls -l testmyisam1*
-rw-r----- 1 mysql mysql 8586 2月  29 09:14 testmyisam1.frm
lrwxrwxrwx 1 mysql mysql   20 2月  29 09:14 testmyisam1.MYD -> /tmp/testmyisam1.MYD
lrwxrwxrwx 1 mysql mysql   20 2月  29 09:14 testmyisam1.MYI -> /tmp/testmyisam1.MYI

 

从上面可以看到,真实数据文件和索引文件放到了指定的目录,但是表定义文件继续放在默认位置,同时MySQL在默认位置还创建了指向真实数据文件和索引文件的链接文件。

MyISAM的表还支持3种不同的存储格式:

  • Static (Fixed-Length) Table,即静态表(固定长度)。这是MyISAM表的默认格式,每行使用固定字节数存储。当表不包含可变长度列(VARCHAR、VARBINARY、BLOB或TEXT)时使用。
  • Dynamic Table,即动态表。如果MyISAM表包含任何可变长度的列(VARCHAR,
    VARBINARY、BLOB或TEXT),或者使用ROW_FORMAT=DYNAMIC选项建表,均会使用动态方式存储。
  • Compressed Table,即压缩表。压缩存储格式是一种只读格式,由myisampack工具生成,用myisamchk解压缩。
root@database-one 09:31:  [gftest]> select * from information_schema.tables where TABLE_SCHEMA='gftest' and TABLE_NAME='testmyisam' \G
*************************** 1. row ***************************
  TABLE_CATALOG: def
   TABLE_SCHEMA: gftest
     TABLE_NAME: testmyisam
     TABLE_TYPE: BASE TABLE
         ENGINE: MyISAM
        VERSION: 10
     ROW_FORMAT: Dynamic
     TABLE_ROWS: 0
 AVG_ROW_LENGTH: 0
    DATA_LENGTH: 0
MAX_DATA_LENGTH: 281474976710655
   INDEX_LENGTH: 1024
      DATA_FREE: 0
 AUTO_INCREMENT: NULL
    CREATE_TIME: 2020-02-29 09:03:55
    UPDATE_TIME: 2020-02-29 09:03:55
     CHECK_TIME: NULL
TABLE_COLLATION: utf8_general_ci
       CHECKSUM: NULL
 CREATE_OPTIONS: 
  TABLE_COMMENT: 
1 row in set (0.06 sec)

root@database-one 09:32:  [gftest]> create table testmyisam2(id int,name char(10),primary key(id)) engine=myisam;
Query OK, 0 rows affected (4.16 sec)

root@database-one 09:34:  [gftest]> select * from information_schema.tables where TABLE_SCHEMA='gftest' and TABLE_NAME='testmyisam2' \G
*************************** 1. row ***************************
  TABLE_CATALOG: def
   TABLE_SCHEMA: gftest
     TABLE_NAME: testmyisam2
     TABLE_TYPE: BASE TABLE
         ENGINE: MyISAM
        VERSION: 10
     ROW_FORMAT: Fixed
     TABLE_ROWS: 0
 AVG_ROW_LENGTH: 0
    DATA_LENGTH: 0
MAX_DATA_LENGTH: 9851624184872959
   INDEX_LENGTH: 1024
      DATA_FREE: 0
 AUTO_INCREMENT: NULL
    CREATE_TIME: 2020-02-29 09:34:00
    UPDATE_TIME: 2020-02-29 09:34:00
     CHECK_TIME: NULL
TABLE_COLLATION: utf8_general_ci
       CHECKSUM: NULL
 CREATE_OPTIONS: 
  TABLE_COMMENT: 
1 row in set (0.02 sec)

 

可以看到,testmyisam表因为name列是varchar类型,所以存储格式为动态的(ROW_FORMAT: Dynamic),testmyisam2表因为name列是char类型,所以存储格式为静态的(ROW_FORMAT: Fixed)。

静态表中字段都是非变长字段,每条记录都是固定长度,存储速度非常快,容易缓存,出现故障容易恢复,缺点是占用空间通常比动态表多。静态表的数据在存储时会按照列宽补足空格,但在数据读取时会去掉空格,这对那些内容后面本来就有空格的场景需要特别注意,否则可能会引发问题。

root@database-one 09:44:  [gftest]> insert into testmyisam2 values(1,'abc'),(2,'abc '),(3,' abc'),(4,' abc ');
Query OK, 4 rows affected (0.00 sec)
Records: 4  Duplicates: 0  Warnings: 0

root@database-one 09:45:  [gftest]> select id,name,length(name) from testmyisam2;
+----+------+--------------+
| id | name | length(name) |
+----+------+--------------+
|  1 | abc  |            3 |
|  2 | abc  |            3 |
|  3 |  abc |            4 |
|  4 |  abc |            4 |
+----+------+--------------+
4 rows in set (0.03 sec)

 

而动态表就不会存在这个问题:

root@database-one 09:47:  [gftest]> insert into testmyisam values(1,'abc'),(2,'abc '),(3,' abc'),(4,' abc ');
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

root@database-one 09:47:  [gftest]> select id,name,length(name) from testmyisam;
+----+-------+--------------+
| id | name  | length(name) |
+----+-------+--------------+
|  1 | abc   |            3 |
|  2 | abc   |            4 |
|  3 |  abc  |            4 |
|  4 |  abc  |            5 |
+----+-------+--------------+
4 rows in set (0.04 sec)

 

动态表中因为包含变长字段,记录长度是不固定的,占用空间相对较少,但是频繁更新和删除会产生碎片,影响性能,需要定期进行optimize table或myisamchk -r来改善性能。

root@database-one 09:47:  [gftest]> optimize table testmyisam;
+-------------------+----------+----------+----------+
| Table             | Op       | Msg_type | Msg_text |
+-------------------+----------+----------+----------+
| gftest.testmyisam | optimize | status   | OK       |
+-------------------+----------+----------+----------+
1 row in set (0.06 sec)

 

© 2020, morinson. 版权所有. 欢迎转载,但请保留作者及出处。