发送 DELETE 查询时,innoDB 是从数据库中逐条删除数据,还是首先创建要删除的数据列表?

When sending a DELETE query, does innoDB delete data from database one-by-one, or first create a list of data to be deleted?

我有一个包含约 140,000 行的数据库 table,现在我正在执行一个类似

的查询
DELETE FROM database WHERE type="delete"

但这需要很长时间。我很想停止查询,看看数据库的大小是否真的缩小了,但我不确定它是否正在创建要删除的数据列表,然后才会实际删除数据。 innoDB 如何在收到 DELETE 查询时实际清除数据库中的数据?

这是 CREATE 查询(针对 table images):

CREATE TABLE IF NOT EXISTS `images` (
  `imageID` int(11) NOT NULL AUTO_INCREMENT,
  `runID_fk` int(11) DEFAULT NULL,
  `sequenceID_fk` int(11) DEFAULT NULL,
  `cameraID_fk` int(11) DEFAULT NULL,
  `data` longblob,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `name` text,
  `type` text,
  `pcadata` longblob,
  PRIMARY KEY (`imageID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

根据您的 CREATE 声明,您在 type 列上没有索引。因此,您的问题是由于 WHERE 子句缓慢造成的。基本上,您的查询会强制数据库服务器查看每一行,以查看 type 列中的值是否为 "delete"。这很慢,不管你有多少行。索引会使这变得更快,因为服务器基本上可以只请求所有匹配行的列表,然后只对这些行进行操作。

作为一个非常广泛的经验法则,如果您打算在 WHERE 子句中使用一个列,则应该对其进行索引。 (当然有例外,但根据您发布的内容,这不是其中之一。)

您可以通过 运行 一个 EXPLAIN 查询查看数据库服务器正在做什么,如

EXPLAIN DELETE FROM database WHERE type="delete"

根据您的评论,您的 EXPLAIN returns 是这样的:

id   select_type   table    partitions   type   possible_keys   key     key_len   ref    rows     filtered  Extra
1    SIMPLE        images                ALL    null            null    null      null   145669             Using where

您看到的 145,699 不是(如您在评论中所写)"the size of the rows."它是服务器执行查询时必须查看的行数。如您所见,它没有任何可以使用的索引。因此,它不仅要查看要删除的行,还必须查看 145,669 行。

此外,由于您的 type 列是 TEXT 列,这会更慢。如果您打算以这种方式标记要删除的行,您应该认真考虑添加 TINYINTCHAR(而不是 TEXT)或其他列来存储行的状态。

更笼统地说,您确实应该重新考虑其中一些列类型。例如,我严重怀疑名为 name 的列是否需要 2^16 - 1 字节。

  • INDEX 已经提到了。
  • TEXT 列(其中有 4 列)可能存储在其他地方,需要额外的磁盘命中。 (已经提到)。
  • InnoDB 构建了一个列表,列出了在发生崩溃时要撤消的事情;这可能是最大的成本。
  • 分块删除不超过 1000 行是一个更好的主意。遍历 PRIMARY KEY 找到区块。
  • 如果这是一项重复性任务,还有其他技巧。
  • 如果删除超过 table 的一半,则:创建新的 table; INSERT SELECT复制守门员; RENAME TABLE 交换; DROP.

有关最后三个建议的详细信息,请参阅 this