Mysql 尝试高效地删除具有多列索引的表中的记录

Mysql 尝试高效地删除具有多列索引的表中的记录,mysql,database,performance,Mysql,Database,Performance,我正在Linux RHEL上使用MySQL 5.6。数据库客户端是一个Java程序。有问题的MyISAM或InnoDB表都有一个多列索引,包含来自其他表的两个整数id和一个时间戳 我想删除在给定日期之前有时间戳的记录。我发现在一个有几百万条记录的表中,这个操作相对较慢,大约30秒。但我还发现,如果指定了索引中的其他两个字段,则操作速度要快得多。这没什么大不了的 我相信我可以查询两个非时间戳表的索引值,然后循环执行delete操作,每次为每个id指定一个值。我希望这不会花太长时间;我还没试过。但是

我正在Linux RHEL上使用MySQL 5.6。数据库客户端是一个Java程序。有问题的MyISAM或InnoDB表都有一个多列索引,包含来自其他表的两个整数id和一个时间戳

我想删除在给定日期之前有时间戳的记录。我发现在一个有几百万条记录的表中,这个操作相对较慢,大约30秒。但我还发现,如果指定了索引中的其他两个字段,则操作速度要快得多。这没什么大不了的

我相信我可以查询两个非时间戳表的索引值,然后循环执行delete操作,每次为每个id指定一个值。我希望这不会花太长时间;我还没试过。但是看起来我应该能够让MySQL为我做循环。我试着查询一下表格

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'