0

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

我想删除在给定日期之前具有时间戳的记录。我发现此操作相对较慢(在具有几百万条记录的表中大约需要 30 秒)。但是我也发现,如果指定索引中的另外两个字段,操作会快很多。那里没有什么大惊喜。

我相信我可以查询两个非时间戳表的索引值,然后循环删除操作,每次指定每个 id 的一个值。我希望这不会花太长时间;我还没试过。但似乎我应该能够让 MySQL 为我做循环。我尝试了表单的查询

delete from mytable where timestamp < '2013-08-17'
    and index1 in (select id from foo)
    and index2 in (select id from bar);

但这实际上比

delete from mytable where timestamp < '2013-08-17';

两个问题。(1)我可以做些什么来加快仅依赖于时间戳的删除操作?(2) 如果做不到这一点,我可以做些什么来让 MySQL 循环遍历另外两个索引列(并快速完成)?

实际上,我对具有相同数据的 MyISAM 和 InnoDB 表都尝试了此操作——它们的速度大致相同。

提前感谢您对这个问题的任何了解。

编辑:有关表结构的更多信息。这是输出show create table mytable

CREATE TABLE `mytable` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `timestamp` datetime NOT NULL,
  `fooId` int(10) unsigned NOT NULL,
  `barId` int(10) unsigned NOT NULL,
  `baz` double DEFAULT NULL,
  `quux` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `fooId` (`fooId`,`barId`,`timestamp`)
) ENGINE=InnoDB AUTO_INCREMENT=14221944 DEFAULT CHARSET=latin1 COMMENT='stuff'

这是输出show indexes from mytable

+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| 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                                        |
+----+-------------+-------+-------+---------------+---------+---------+-------------------------------+------+----------------------------------------------------+
4

2 回答 2

0

忘记其他两个ID。仅在时间戳上添加索引。否则你可能会遍历整个表。

于 2013-09-19T22:33:02.000 回答
0

使用多表DELETE语法连接表:

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 的话当然会是这种情况),这应该会表现得特别好。

于 2013-09-18T21:08:22.307 回答