Mic*_*ael 4 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';
Run Code Online (Sandbox Code Playgroud)
> Dynamic
SELECT row_format FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable2';
Run Code Online (Sandbox Code Playgroud)
> Fixed
更新 2012-12-09 08:06
LOAD DATA
当且仅当行格式是固定的或(行格式是动态的并且有一个大小完全相同的已删除行)时,do 重用以前删除的空间(我已经通过运行一个简短的脚本进行了检查)。
好像如果row_format是动态的,就对每条记录进行完整的删除列表查找,如果没有找到确切的行大小,则不使用删除的记录,表内存使用量会增加,另外LOAD DATA
还会需要更多时间来导入记录。
我会排除这里给出的答案,因为它完美地描述了所有过程。
对于名为的 MySQL 表,mydb.mytable
只需运行以下命令:
OPTIMIZE TABLE mydb.mytable;
Run Code Online (Sandbox Code Playgroud)
您也可以分阶段执行此操作:
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;
Run Code Online (Sandbox Code Playgroud)
在任何一种情况下,表最终都没有碎片。
试一试 !!!
如果您担心在通过 批量LOAD DATA INFILE
插入时是否重复使用行,请注意以下几点:
创建 MyISAM 表时,我假设默认行格式是动态的。你可以检查它是什么
SHOW CREATE TABLE mydb.mytable\G
Run Code Online (Sandbox Code Playgroud)
或者
SELECT row_format FROM information_schema.tables
WHERE table_schema='mydb' AND table_name='mytable';
Run Code Online (Sandbox Code Playgroud)
由于您的表的行格式是Dynamic
,因此碎片行的大小各不相同。MyISAM 存储引擎将不断检查每个删除的行长度,以查看下一组插入的数据是否适合。如果传入的数据无法放入任何已删除的行中,则会附加新的行数据。
这就是为什么我建议运行OPTIMIZE TABLE
. 这样,数据将被更快地附加。
您还可以执行以下有趣的操作:尝试将 concurrent_insert 设置为 2。这样,您总是在不检查表中的间隙的情况下附加到 MyISAM 表。这将显着加快 INSERT 的速度,但不会影响所有已知的间隙。
您仍然可以在方便的时候尽早使用OPTIMIZE TABLE
.
为什么不运行我的第二个建议
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;
Run Code Online (Sandbox Code Playgroud)
这会给你一个想法
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;
Run Code Online (Sandbox Code Playgroud)
任何 ROW_FORMAT 设置为固定的表都可以每次都分配相同长度的行。如果 MyISAM 表维护已删除行的列表,则应始终选择列表中的第一行作为插入数据的下一行。在找到具有足够长度的合适行间隙之前,不需要遍历整个列表。每个删除的行都快速附加在DELETE
. 每个 INSERT 都会选择已删除行的第一行。
我们可以假设这些事情,因为MyISAM 表可以执行并发插入。为了通过concurrent_insert选项可以使用此功能,到 MyISAM 表的 INSERT 必须能够检测三 (3) 件事之一:
为了使检测 #1 尽可能快,MyISAM 表的 row_format 必须是固定的。如果是动态的,很有可能需要进行列表遍历。