mysql - LOAD DATA 删除后回收磁盘空间

标签 mysql load-data-infile

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

我知道 delete 不会回收内存空间,但是正如我在 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';

> 动态

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

> 固定

更新 2012-12-09 08:06

LOAD DATA 当且仅当行格式是固定的或(行格式是动态的并且有删除的行大小完全相同)。

看来如果row_format是动态的,对每条记录都会在删除列表中进行全量查找,如果没有找到准确的行大小,则不使用删除的记录,表内存占用会增加, 此外 LOAD DATA 将花费更多时间来导入记录。

我将排除此处给出的答案,因为它完美地描述了所有过程。

最佳答案

对于名为 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 批量插入时行是否被重用,请注意以下几点:

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

SHOW CREATE TABLE mydb.mytable\G

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

由于您的表的行格式是动态,因此碎片行的大小各不相同。 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 EDT

为什么不运行我的第二个建议

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.MYI 在运行 OPTIMIZE 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 提供此功能选项,插入 MyISAM 表必须能够检测到三 (3) 个事物之一:

  1. 存在已删除行的列表,从而从列表中进行选择
    • Row_Format=Dynamic :已删除行的列表,每行具有不同的长度
    • Row_Format=Fixed : 所有行长度相同的已删除行列表
  2. 缺少已删除行的列表,因此追加
  3. 绕过检查是否存在已删除行列表(将 concurrent_insert 设置为 2)

为了使检测 #1 尽可能快,MyISAM 表的 row_format 必须固定。如果是Dynamic,很有可能需要遍历列表。

关于mysql - LOAD DATA 删除后回收磁盘空间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13685949/

相关文章:

当仍需要实时 SELECT 查询时 MySQL 锁定处理大型 LOAD DATA INFILE

php - Wordpress 完全删除自定义帖子类型

mysql - 我可以将硬编码字符串与 MySQL LOAD DATA INFILE 中的列连接起来吗?

sql - mysql "datetime NOT NULL DEFAULT ' 1970-01-0 1' "变成 0000-00-00 00 :00:00

'load data' 的 Mysql 权限错误

Java mySQL登录问题

php - 选择多次存在且存在变化的行

php - 如何在php中显示来自mysql的图像

mySQL phpmyadmin - 默认情况下小写数据

MySQL load data infile 恰好加载一半的记录