您在有关 MyISAM 的问题中获得的信息是正确的。但是,我想解决您的另外两个问题:
最新问题
如果用户使用更长的数据更新现有数据怎么办?MyISAM 会将记录标记为已删除并找到适合新数据的位置还是简单地使用溢出指针指向不适合的数据?
根据书

第 10 章:“存储引擎”第 196 页第 7 段说
对于可变长度的记录,格式更复杂。第一个字节包含描述记录子类型的特殊代码。后续字节的含义因每个子类型而异,但共同的主题是有一个字节序列,其中包含记录的长度、块中未使用的字节数、NULL 值指示标志,以及可能指向的指针如果记录不适合先前创建的空间并且必须拆分,则继续记录。当一条记录被删除并且要插入其位置的新记录超过原始记录的大小时,可能会发生这种情况。您可以通过研究 storage/myisam/mi_dynrec.c 中的 switch 语句 in_mi_get_block_info() 来了解不同代码的含义的详细信息。
根据该段,仅当要插入的新数据无法放入先前分配的块中时,旧记录才会被链接数据覆盖。这可能会导致许多臃肿的行。
附加问题
如果表被多次删除和插入,是否会非常低效,因为记录结构可能充满溢出指针和未使用的空间?
从我之前的回答来看,会有很多块
- 空间块
- 记录的长度
- 块中未使用的字节数
- NULL 值指示标志
- 如果记录不适合先前创建的空间并且必须拆分,则可能是指向记录延续的指针
这样的记录链接将从插入过大数据的每一行的前面开始。这会使 MyISAM 表.MYD文件很快膨胀。
建议
MyISAM 的默认行格式是动态的。当一个表是动态的并且经历大量的插入、更新和删除时,这样的表需要使用优化
OPTIMIZE TABLE mytable;
还有一种选择:将表格的行格式切换为固定。这样,所有行的大小都相同。这是使行格式固定的方式:
ALTER TABLE mytable ROW_FORMAT=Fixed;
即使使用固定行格式,也必须花费时间来定位可用记录,但时间将是 O(1) 搜索时间(通俗地说,无论有多少行,定位可用记录都需要相同的时间该表有或有多少已删除的行)。您可以通过启用concurrent_insert来绕过该步骤,如下所示:
将此添加到 my.cnf
[mysqld]
concurrent_insert = 2
不需要重启 MySQL。赶紧跑
mysql> SET GLOBAL concurrent_insert = 2;
这将导致所有 INSERT 转到表的后面而不寻找可用空间。
固定行表的优势
- 插入、更新和删除会更快一些
- SELECT 快 20-25%
这是我的一些关于 SELECT 更快的帖子,因为行格式被修复
固定行表的缺点
在大多数情况下,当您运行时ALTER TABLE mytable ROW_FORMAT=Fixed;,表可能会增长 80-100%。文件(MyISAM 表的.MYI索引页)也会以同样的速度增长。
结语
如果您想要 MyISAM 表的速度并且可以使用更大的表,则需要我的替代建议。如果您想为每个 MyISAM 表节省空间,请将行格式保留为(动态)。您将不得不OPTIMIZE TABLE mytable;使用动态表更频繁地压缩表。