Mysql 尝试高效地删除具有多列索引的表中的记录
我正在Linux RHEL上使用MySQL 5.6。数据库客户端是一个Java程序。有问题的MyISAM或InnoDB表都有一个多列索引,包含来自其他表的两个整数id和一个时间戳 我想删除在给定日期之前有时间戳的记录。我发现在一个有几百万条记录的表中,这个操作相对较慢,大约30秒。但我还发现,如果指定了索引中的其他两个字段,则操作速度要快得多。这没什么大不了的 我相信我可以查询两个非时间戳表的索引值,然后循环执行delete操作,每次为每个id指定一个值。我希望这不会花太长时间;我还没试过。但是看起来我应该能够让MySQL为我做循环。我试着查询一下表格Mysql 尝试高效地删除具有多列索引的表中的记录,mysql,database,performance,Mysql,Database,Performance,我正在Linux RHEL上使用MySQL 5.6。数据库客户端是一个Java程序。有问题的MyISAM或InnoDB表都有一个多列索引,包含来自其他表的两个整数id和一个时间戳 我想删除在给定日期之前有时间戳的记录。我发现在一个有几百万条记录的表中,这个操作相对较慢,大约30秒。但我还发现,如果指定了索引中的其他两个字段,则操作速度要快得多。这没什么大不了的 我相信我可以查询两个非时间戳表的索引值,然后循环执行delete操作,每次为每个id指定一个值。我希望这不会花太长时间;我还没试过。但是
delete from mytable where timestamp < '2013-08-17'
and index1 in (select id from foo)
and index2 in (select id from bar);
以下是mytable中显示索引的输出:
编辑:更多信息-解释输出
mysql> explain delete from mytable using mytable inner join foo inner join bar where mytable.fooId=foo.id and mytable.barId=bar.id and timestamp<'2012-08-27';
+----+-------------+-------+-------+---------------+---------+---------+-------------------------------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------------------------------+------+----------------------------------------------------+
| 1 | SIMPLE | foo | index | PRIMARY | name | 257 | NULL | 26 | Using index |
| 1 | SIMPLE | bar | index | PRIMARY | name | 257 | NULL | 38 | Using index; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE |mytable| ref | fooId | fooId | 8 | foo.foo.id,foo.bar.id | 211 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+-------------------------------+------+----------------------------------------------------+
使用多表删除语法联接表:
DELETE mytable
FROM mytable
JOIN foo ON foo.id = mytable.index1
JOIN bar ON bar.id = mytable.index2
WHERE timestamp < '2013-08-17'
我认为,如果mytable在index1、index2、timestamp上有一个复合索引,并且foo和bar在它们的id列上都有索引,那么这应该表现得特别好。当然,如果这些列是PK的话,情况就是这样。忘掉其他两个id。仅在时间戳上添加索引。否则,您可能会遍历整个表。您还可以发布一些关于表结构的信息吗?show create tablecommand@RaymondNijland:我添加了show create table的输出和show indexes的输出。谢谢你的建议。那桌子呢?但问题是,您想要删除一个较大的选择,这意味着您的BTREE索引需要很好地更新,这将减慢您的删除速度。我不知道您的选择匹配了多少条记录,也许您也可以在大型innodb表上运行count*注意,这可能需要5到10分钟。然后使用mytable内部连接foo内部连接栏从mytable中选择count*,其中mytable.fooId=foo.id和mytable.barId=bar.id和timestampYes,id是foo和bar的主键,index1,在index2中,timestamp是mytable的复合键。我按照你的建议尝试了这个查询,但不幸的是我发现它并没有更快。谢谢你的建议,我很感激。@RobertDodier:你能在你的问题中加入解释计划吗?我已经把解释的结果加入了问题中。谢谢你的建议。谢谢你的回复。我不太明白你的意思。唯一性约束对于表的含义很重要。你的意思是,只在时间戳上添加另一个索引吗?我不知道这是否可能。也许我误解了你的意思;也许你可以澄清一下,“在时间戳上添加索引”正是我所说的。我不明白这怎么可能被误解。这在技术上当然是可能的。当然,让它成为非唯一的。在完成这项工作时,您可能会遇到dbadmin问题,但由于它解决了这个性能问题,因此确实没有争议的余地。
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
|mytable| 0 | PRIMARY | 1 | id | A | 2612681 | NULL | NULL | | BTREE | | |
|mytable| 0 | fooId | 1 | fooId | A | 20 | NULL | NULL | | BTREE | | |
|mytable| 0 | fooId | 2 | barId | A | 3294 | NULL | NULL | | BTREE | | |
|mytable| 0 | fooId | 3 | timestamp | A | 2612681 | NULL | NULL | | BTREE | | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
mysql> explain delete from mytable using mytable inner join foo inner join bar where mytable.fooId=foo.id and mytable.barId=bar.id and timestamp<'2012-08-27';
+----+-------------+-------+-------+---------------+---------+---------+-------------------------------+------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------------------------------+------+----------------------------------------------------+
| 1 | SIMPLE | foo | index | PRIMARY | name | 257 | NULL | 26 | Using index |
| 1 | SIMPLE | bar | index | PRIMARY | name | 257 | NULL | 38 | Using index; Using join buffer (Block Nested Loop) |
| 1 | SIMPLE |mytable| ref | fooId | fooId | 8 | foo.foo.id,foo.bar.id | 211 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+-------------------------------+------+----------------------------------------------------+
DELETE mytable
FROM mytable
JOIN foo ON foo.id = mytable.index1
JOIN bar ON bar.id = mytable.index2
WHERE timestamp < '2013-08-17'