mysql – 如何在大型InnoDB表上提高DELETE FROM性能?

我有一个相当大的InnoDB表,其中包含大约1000万行(并且计数,这将是20倍的大小).每一行都不是那么大(平均为131 B),但是我不时要删除一大块,而这正在耗费时间.这是表结构:

 CREATE TABLE `problematic_table` (
    `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    `taxid` int(10) unsigned NOT NULL,
    `blastdb_path` varchar(255) NOT NULL,
    `query` char(32) NOT NULL,
    `target` int(10) unsigned NOT NULL,
    `score` double NOT NULL,
    `evalue` varchar(100) NOT NULL,
    `log_evalue` double NOT NULL DEFAULT '-999',
    `start` int(10) unsigned DEFAULT NULL,
    `end` int(10) unsigned DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `taxid` (`taxid`),
    KEY `query` (`query`),
    KEY `target` (`target`),
    KEY `log_evalue` (`log_evalue`)
) ENGINE=InnoDB AUTO_INCREMENT=7888676 DEFAULT CHARSET=latin1;

从表中删除大块的查询只是这样:

DELETE FROM problematic_table WHERE problematic_table.taxid = '57';

像这样的查询刚刚花了将近一个小时才能完成.我可以想象,索引重写开销使得这些查询非常慢.

我正在开发一个将在预先存在的数据库上运行的应用程序.我很可能无法控制服务器变量,除非我对它们进行了更改(我不想这样做),所以我担心改变这些变量的建议是没有价值的.

我试图INSERT …选择我不想删除到临时表中的行,只是删除其余的行,但是由于删除与否的比例保持不变,这是不再有用的解决方案.

这是一个可能会在以后看到频繁的INSERT和SELECT的表,但没有UPDATE.基本上,它是一个日志和参考表,需要不时地删除其内容的一部分.

我可以通过限制长度来改善我在这张桌子上的索引吗?会切换到MyISAM帮助,它在事务期间支持DISABLE KEYS?还可以尝试提高DELETE性能?

编辑:一个这样的删除将是大约一百万行的顺序.

最佳答案
该解决方案可以在完成后提供更好的性能,但该过程可能需要一些时间才能实现.

可以添加一个新的BIT列,默认为“active”,FALSE为“inactive”.如果状态不够,可以使用TINYINT 256个可能的值.

添加这个新列可能需要很长时间,但是一旦结束,只要您从PRIMARY执行删除操作,您的更新应该快得多,并且不要对此新列进行索引.

为什么InnoDB需要如此长时间才能在这样一个庞大的表上删除您的原因是因为集群索引.它根据您的PRIMARY,它发现的第一个UNIQUE,或者如果它找不到PRIMARY或UNIQUE可以确定为足够的替代物,那么它实际上会命令您的表,所以当一行被删除时,它现在将在整个表上物理上重新排序磁盘用于速度和碎片整理.所以这不是DELETE这么长时间;这是行删除后的物理重新排序.

当您创建一个固定宽度的列并更新而不是删除时,不需要跨巨大的表进行物理重新排序,因为行和表本身消耗的空间是不变的.

在休息时间内,可以使用单个DELETE来删除不必要的行.此操作仍然很慢,但总体上比删除单个行要快得多.

转载注明原文:mysql – 如何在大型InnoDB表上提高DELETE FROM性能? - 代码日志