删除后LOAD DATA回收磁盘空间

时间:2012-12-03 15:05:14

标签: mysql load-data-infile

我有一个由MYISAM表组成的数据库模式,我有兴趣从某些表中不时删除旧记录。

我知道删除不会回收内存空间,但正如我在DELETE命令的描述中找到的那样,插入可能会重用已删除的空间

在MyISAM表中,删除的行保存在链表中,后续的INSERT操作重用旧行位置。

如果LOAD DATA命令也重用了已删除的空格,我感兴趣吗?

更新

我也对索引空间如何回收感兴趣?

更新2012-12-03 23:11

根据从@RolandoMySQLDBA收到的答案提供的更多信息

执行以下建议的查询后,对于需要重用或回收空间的不同表,我得到了不同的结果:

SELECT row_format FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable1';

> Dynamic

SELECT row_format FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable2';

> Fixed

更新2012-12-09 08:06

LOAD DATA重复使用以前删除的空间(我已经通过运行短脚本检查了它)当且仅当行格式是固定的或(行格式是动态的并且删除的行完全相同)尺寸)。

似乎如果row_format是动态的,则对每个记录进行完全查找已删除列表,如果找不到确切的行大小,则不使用已删除的记录,并且表内存使用率将提高另外LOAD DATA将需要更多时间来导入记录。

我会在这里给出答案,因为它完整地描述了所有过程。

1 个答案:

答案 0 :(得分:4)

对于名为mydb.mytable的MySQL表,只需运行以下命令:

OPTIMIZE TABLE mydb.mytable;

您也可以分阶段执行此操作:

CREATE TABLE mydb.mytable_new LIKE mydb.mytable;
ALTER TABLE mydb.mytable_new DISABLE KEYS;
INSERT INTO mydb.mytable_new SELECT * FROM mydb.mytable;
ALTER TABLE mydb.mytable_new ENABLE KEYS;
ALTER TABLE mydb.mytable RENAME mydb.mytable_old;
ALTER TABLE mydb.mytable_new RENAME mydb.mytable;
ALTER TABLE mydb.mytable_old;
ANALYZE TABLE mydb.mytable;

在任何一种情况下,该表最终都没有碎片。

试一试!!!

更新2012-12-03 12:50 EDT

如果您担心是否可以通过LOAD DATA INFILE对批量INSERT重复使用行,请注意以下事项:

当您创建MyISAM表时,我假设默认行格式是动态的。你可以用

来检查它是什么
SHOW CREATE TABLE mydb.mytable\G

SELECT row_format FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';

由于表的行格式为Dynamic,因此碎片行的大小各不相同。 MyISAM存储引擎会不断检查每个已删除的行长度,以查看下一组插入的数据是否合适。如果传入的数据不适合任何已删除的行,则会追加新的行数据。

The presence of such rows can make myisamchk struggle

这就是为什么我建议运行OPTIMIZE TABLE。这样,数据就会更快地附加。

更新2012-12-03 12:58 EDT

以下是您可以做的有趣事情:Try setting concurrent_insert to 2。这样,您总是会附加到MyISAM表而不检查表中的间隙。这将大大加快INSERT的速度,但仅留下所有已知的差距。

您仍然可以使用OPTIMIZE TABLE尽早对桌面进行碎片整理。

更新2012-12-03 13:40美国东部时间

为什么不运行我的第二次诉讼

CREATE TABLE mydb.mytable_new LIKE mydb.mytable;
ALTER TABLE mydb.mytable_new DISABLE KEYS;
INSERT INTO mydb.mytable_new SELECT * FROM mydb.mytable;
ALTER TABLE mydb.mytable_new ENABLE KEYS;
ALTER TABLE mydb.mytable RENAME mydb.mytable_old;
ALTER TABLE mydb.mytable_new RENAME mydb.mytable;
ANALYZE TABLE mydb.mytable;

这会给你一个想法

  • OPTIMIZE TABLE需要多长时间才能运行
  • 运行.MYD
  • 后,.MYIOPTIMIZE TABLE会变小多少

运行我的第二个建议后,您可以将它们与

进行比较
SELECT
    A.mydsize,B.mydsize,A.mydsize - B.mydsize myd_diff,
    A.midsize,B.myisize,A.myisize - B.myisize myi_diff
FROM
(
    SELECT data_length mydsize,index_length myisize
    FROM information_schema.tables
    WHERE table_schema='mydb' AND table_name='mytable'
) A,
(
    SELECT data_length mydsize,index_length myisize
    FROM information_schema.tables
    WHERE table_schema='mydb' AND table_name='mytable_new'
) B;

更新2012-12-03 16:42 EDT

任何将ROW_FORMAT设置为固定的表都可以每次分配相同长度的行。如果MyISAM表维护已删除行的列表,则应始终选择列表中的第一行作为插入数据的下一行。在找到具有足够长度的合适行间隙之前,不需要遍历整个列表。在DELETE之后快速追加每个已删除的行。每个INSERT都会选择已删除行的第一行。

我们可以假设这些事情,因为MyISAM tables can do concurrent inserts。为了通过concurrent_insert选项提供此功能,INSERT到MyISAM表必须能够检测到三(3)件事中的一件:

  1. 存在已删除行的列表,从而从列表中进行选择
    • Row_Format =动态:已删除行的列表,每行的长度不同
    • Row_Format =已修复:所有行长度相同的已删除行列表
  2. 缺少已删除行的列表,因此附加
  3. 绕过检查是否存在已删除的行列表(将concurrent_insert设置为2)
  4. 为了使检测#1尽可能快,MyISAM表的row_format必须是固定的。如果它是动态的,则很可能需要列表遍历。