MyISAM表的存储格式
1. 静态(固定长度)表特征
2. 动态表特征
3. 已压缩表特征
MyISAM支持三种不同存储格式。其中两个(固定格式和动态格式)根据正使用的列的类型来自动选择。第三个,即已压缩格式,只能使用myisampack工具来创建。
当CREATE或ALTER一个没有BLOB或TEXT列的表,可以用ROW_FORMAT表选项强制表的格式为FIXED或DYNAMIC。这会导致CHAR和VARCHAR列因FIXED格式变成CHAR,或因DYNAMIC格式变成VARCHAR。
通过用ALTER TABLE指定ROW_FORMAT={COMPRESSED | DEFAULT},可以压缩或解压缩表,
15.1.3.1. 静态(固定长度)表特征
静态格式是MyISAM表的默认存储格式。当表不包含变量长度列(VARCHAR, BLOB, 或TEXT)时,使用这个格式。每一行用固定字节数存储。
MyISAM的三种存储格式中,静态格式就最简单也是最安全的(至少对于崩溃而言)。静态格式也是最快的on-disk格式。快速来自于数据文件中的行在磁盘上被找到的容易方式:当按照索引中的行号查找一个行时,用行长度乘以行号。同样,当扫描一个表的时候,很容易用每个磁盘读操作读一定数量的记录。
当MySQL服务器正往一个固定格式MyISAM文件写的时候,如果计算机崩溃了,安全是显然的。在这种情况下,myisamchk可以容易地决定每行从哪里开始到哪里结束,所以它通常可以收回所有记录,除了写了一部分的记录。注意,基于数据行,MyISAM表索引可以一直被重新构建。
静态格式表的一般特征:
·CHAR列对列宽度是空间填补的。
·非常快。
·容易缓存。
·崩溃后容易重建,因为记录位于固定位置。
·重新组织是不必要的,除非你删除巨量的记录并且希望为操作系统腾出磁盘空间。为此,可使用OPTIMIZE TABLE或者myisamchk -r。
·通常比动态格式表需要更多的磁盘空间。
静态表的数据在存储的收获会按照列的宽度定义补足空格,但是在应用访问的时候并不会得到这些空格,这些空格在返回给应用程序之前就被去掉了。
mysql> insert into myisam_char values('abcde'),(' abcde'),('yangql '),(' xxq ');
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0
mysql> select val ,length(val) from myisam_char;
+---------+-------------+
| val | length(val) |
+---------+-------------+
| abcde | 5 |
| abcde | 7 |-前面的空格保留
| yangql | 6 |-空格被去掉
| xxq | 4 |-空格被去掉
+---------+-------------+
4 rows in set (0.00 sec)
15.1.3.2. 动态表特征
如果一个MyISAM表包含任何可变长度列(VARCHAR, BLOB或TEXTDynamic),或者如果一个表被用ROW_FORMAT=DYNAMIC选项来创建,动态存储格式被使用。
动态表的格式比较复杂,因为每行有一个表明行有多长的头。当一个记录因为更新的结果被变得更长,该记录也可以在超过一个位置处结束。
你可以使用OPTIMIZE TABLE或myisamchk来对一个表整理碎片。如果在一个表中有你频繁访问或改变的固定长度列,表中也有一些可变长度列,仅为避免碎片而把这些可变长度列移到其它表。
动态格式表的一般特征:
·除了长度少于4的列外,所有的字符串列是动态的。
·在每个记录前面是一个位图,该位图表明哪一列包含空字符串(对于字符串列)或者0(对于数字列)。注意,这并不包括包含NULL值的列。如果一个字符列在拖曳空间移除后长度为零,或者一个数字列为零值,这都在位图中标注了且列不被保存到磁盘。 非空字符串被存为一个长度字节加字符串的内容。
·通常比固定长度表需要更少的磁盘空间。
·每个记录仅使用必需大小的空间。尽管如此,如果一个记录变大,它就按需要被分开成多片,造成记录碎片的后果。比如,你用扩展行长度的信息更新一行,该行就变得有碎片。在这种情况下,你可以时不时运行OPTIMIZE TABLE或myisamchk -r来改善性能。可使用myisamchk -ei来获取表的统计数据。
·动态格式表在崩溃后要比静态格式表更难重建,因为一个记录可能被分为多个碎片且链接(碎片)可能被丢失。
·动态尺寸记录期望的行长度用下列表达式来计算:
·3
·+ (number of columns + 7) / 8
·+ (number of char columns)
·+ (packed size of numeric columns)
·+ (length of strings)
·+ (number of NULL columns + 7) / 8
对每个链接需要额外的6字节。在一个更新导致一个记录的扩大之时,一个动态记录被链接了。每个新链接至少是20字节,所以下一个扩大可能在同样的链接里进行。如果不是,则另一个链接将被建立。你可以使用myisamchk -ed来找出链接的数目。所有的链接可以用myisamchk -r来移除。
15.1.3.3. 已压缩表特征
已压缩存储格式是由myisampack工具创建的只读格式。
所有MySQL分发版里都默认包括myisampack。已压缩表可以用myisamchk来解压缩。
已压缩表有下列特征:
·已压缩表占据非常小的磁盘空间。这最小化了磁盘用量,当使用缓慢的磁盘(如CD-ROM)之时,这是很有用的。
·每个记录是被单独压缩的,所以只有非常小的访问开支。依据表中最大的记录,一个记录的头在每个表中占据1到3个字节。每个列被不同地压缩。通常每个列有一个不同的Huffman树。一些压缩类型如下:
o 后缀空间压缩。
- 前缀空间压缩。
- 零值的数用一个位来存储。
- 如果在一个整型列中的值有一个小的范围,列被用最小可能的类型来存储。比如,一个BIGINT列(8字节),如果所有它的值在-128到127范围内,它可以被存储为TINYINT列(1字节)
-如果一个列仅有一小组可能的值,列的类型被转化成ENUM。
-一个列可以使用先前压缩类型的任意合并。
·可以处理固定长度或动态长度记录。
4. MyISAM表方面的问题
1. 损坏的MyISAM表
2. 未被适当关闭的表的问题
MySQL用来存储数据的文件格式已经被广泛测试过,但总是有导致数据表变得损坏的环境。
1. 损坏的MyISAM表
即使MyISAM表格式非常可靠(SQL语句对表做的所有改变在语句返回之前被写下),如果下列任何事件发生,你依然可以获得损坏的表:
·mysqld进程在写中间被杀掉。
·发生未预期的计算机关闭(例如,计算机被关闭)。
·硬件故障。
·你可以同时在正被服务器修改的表上使用外部程序(如myisamchk)。
·MySQL或MyISAM代码的软件缺陷。
一个损坏的表的典型症状如下:
·当在从表中选择数据之时,你得到如下错误:
·Incorrect key file for table: '...'. Try to repair it
·查询不能在表中找到行或返回不完全的数据。
你可以用CHECK TABLE statement语句来检查MyISAM表的健康,并用REPAIR TABLE修复一个损坏的MyISAM表。当mysqld不运行之时,也可以用myisamchk命令检查或修理一个表。
如果你的表变得频繁损坏,你应该试着确定为什么会这样的原因。要明白的最重要的事是表变得损坏是不是因为服务器崩溃的结果。你可以在错误日志中查找最近的restarted mysqld消息来早期验证这个。如果存在这样一个消息,则表损坏是服务器死掉的一个结果是很有可能的。否则,损坏可能在正常操作中发生。
2. 未被适当关闭的表的问题
每个MyISAM索引文件(.MYI)在头有一个计数器,它可以被用来检查一个表是否被恰当地关闭。如果你从CHECK TABLE或myisamchk得到下列警告,意味着这个计数器已经不同步了:
clients are using or haven't closed the table properly
这个警告并不是完全意味着表已被破坏,但你至少应该检查表。
计数器的工作方式如下:
·表在MySQL中第一次被更新,索引文件头的计数器加一。
·在未来的更新中,计数器不被改变。
·当表的最后实例被关闭(因为一个操作FLUSH TABLE或因为在表缓冲区中没有空间)之时,若表已经在任何点被更新,则计数器减一。
·当你修理或检查表并且发现表完好之时,计数器被重置为零。
·要避免与其它可能检查表的进程进行事务的问题,若计数器为零,在关闭时计数器不减一。
换句话来说,计数器只有在下列情况会不同步:
·MyISAM表不随第一次发出的LOCK TABLES和FLUSH TABLES被复制。
·MySQL在一次更新和最后关闭之间崩溃(注意,表可能依然完好,因为MySQL总是在每个语句之间为每件事发出写操作)。
·一个表被myisamchk --recover或myisamchk --update-state修改,同时被mysqld使用。
·多个mysqld服务器正使用表,并且一个服务器在一个表上执行REPAIR TABLE或CHECK TABLE,同时该表也被另一个服务器使用。在这个结构中,使用CHECK TABLE是安全的,虽然你可能从其它服务器上得到警告。尽管如此,REPAIR TABLE应该被避免,因为当一个服务器用一个新的数据文件替代旧的之时,这并没有发送信号到其它服务器上。 总的来说,在多服务器之间分享一个数据目录是一个坏主意。