【发布时间】:2013-01-11 18:16:07
【问题描述】:
我有一个相当大的 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 ... SELECT那些我不想删除到临时表中的行并只是删除其余的行,但是随着删除与保留的比例转向保留,这不再是一个有用的解决方案。
这是一张将来可能会频繁出现INSERTs 和SELECTs 的表格,但不会出现UPDATEs。基本上,它是一个需要不时删除部分内容的日志记录和引用表。
我可以通过限制索引的长度来改进此表上的索引吗?在交易期间切换到支持DISABLE KEYS 的 MyISAM 会有所帮助吗?我还能尝试什么来提高DELETE 的性能?
编辑:这样的删除之一是大约一百万行。
【问题讨论】:
-
它可能没有您需要的那么多帮助,但可以改进数据类型。
id列真的需要是BIGINT吗?INT是大小的一半,最高可达 40 亿,远高于您预计的最大值。query列可能占用了大部分空间。如果不总是 32 个字符,请将其设为VARCHAR。query上的索引也可能是有限的,如果你真的不需要它。 -
@G-Nugget:感谢您的建议。我将考虑将
id转换为INT。是的,query列需要 32 个字符,因为这些是 SHA-256 哈希值。不过,我可能应该限制它的索引。大多数时候,此列用于标识行;如果我将它用作PRIMARY KEY会有帮助吗(id并没有真正用于查找记录)? -
也许这是一个类似的问题,见stackoverflow.com/a/13742306/1741542
-
@inhan:将
BIGINT转换为INT没有任何明显的区别。 -
我的“大删除”论文:mysql.rjweb.org/doc.php/deletebig
标签: mysql performance innodb