### 13.2.2 删除语句

[](<>)[](<>)

[`删除`](delete.html)是从表中删除行的 DML 语句。

一种[`删除`](delete.html)语句可以以 a 开头[`和`](with.html)子句定义可在[`删除`](delete.html).看[第 13.2.15 节，“WITH（公用表表达式）”](with.html).

#### 单表语法

```
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [[AS] tbl_alias]
    [PARTITION (partition_name [, partition_name] ...)]
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]
```

这`删除`语句从中删除行*`tbl_name`*并返回删除的行数。要检查删除的行数，请调用[`ROW_COUNT()`](information-functions.html#function_row-count)中描述的功能[第 12.16 节，“信息功能”](information-functions.html).

#### 主要条款

可选中的条件`在哪里`子句标识要删除的行。没有`在哪里`子句，所有行都被删除。

*`where_condition`*是一个表达式，对于要删除的每一行计算结果为真。它被指定为描述[第 13.2.10 节，“SELECT 语句”](select.html).

如果`订购方式`子句，则按指定的顺序删除行。这`限制`子句限制可以删除的行数。这些子句适用于单表删除，但不适用于多表删除。

#### 多表语法

```
DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    tbl_name[.*] [, tbl_name[.*]] ...
    FROM table_references
    [WHERE where_condition]

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    FROM tbl_name[.*] [, tbl_name[.*]] ...
    USING table_references
    [WHERE where_condition]
```

#### 特权

你需要[`删除`](privileges-provided.html#priv_delete)表中删除行的权限。你只需要[`选择`](privileges-provided.html#priv_select)任何只读列的特权，例如在`在哪里`条款。

#### 表现

当您不需要知道删除的行数时，[`截断表`](truncate-table.html)语句是一种比清空表更快的方法[`删除`](delete.html)没有的声明`在哪里`条款。不像[`删除`](delete.html),[`截断表`](truncate-table.html)不能在事务中使用，或者如果您在表上有锁。看[第 13.1.37 节，“TRUNCATE TABLE 语句”](truncate-table.html)和[第 13.3.6 节，“LOCK TABLES 和 UNLOCK TABLES 语句”](lock-tables.html).

删除操作的速度也可能受中讨论的因素影响[第 8.2.5.3 节，“优化 DELETE 语句”](delete-optimization.html).

为了确保给定的[`删除`](delete.html)语句不需要太多时间，MySQL特有的`限制 *`行数`*`条款[`删除`](delete.html)指定要删除的最大行数。如果要删除的行数大于限制，请重复`删除`语句，直到受影响的行数小于`限制`价值。

#### 子查询

您不能在子查询中从表中删除并从同一个表中进行选择。

#### 分区表支持

`删除`支持使用显式分区选择`划分`子句，它接受一个或多个分区或子分区（或两者）的逗号分隔名称列表，从中选择要删除的行。未包含在列表中的分区将被忽略。给定一个分区表`吨`有一个名为的分区`p0`, 执行语句`从 t 分区中删除 (p0)`对表的影响与执行相同[`ALTER TABLE t 截断分区 (p0)`](alter-table.html);在这两种情况下，分区中的所有行`p0`被丢弃。

`划分`可以与一个`在哪里`条件，在这种情况下，仅在列出的分区中的行上测试条件。例如，`从 t 分区 (p0) 中删除，其中 c < 5`仅从分区中删除行`p0`条件`c < 5`是真的;不检查任何其他分区中的行，因此不受`删除`.

这`划分`子句也可以用在多表中`删除`陈述。每个表中最多可以使用一个这样的选项`从`选项。

有关更多信息和示例，请参阅[第 24.5 节，“分区选择”](partitioning-selection.html).

#### 自动增加列

如果删除包含某个最大值的行`自动递增`列，该值不被重用于`MyISAM`要么`InnoDB`桌子。如果您删除表中的所有行`从 * 中删除`tbl_name`*`（没有`在哪里`子句）在[`自动提交`](server-system-variables.html#sysvar_autocommit)模式下，序列对所有存储引擎重新开始，除了`InnoDB`和`MyISAM`.此行为有一些例外情况`InnoDB`表，如中所述[第 15.6.1.6 节，“自动\_InnoDB 中的增量处理”](innodb-auto-increment-handling.html).

为了`MyISAM`表，您可以指定一个`自动递增`多列键中的辅助列。在这种情况下，重复使用从序列顶部删除的值，即使对于`MyISAM`表。看[第 3.6.9 节，“使用 AUTO\_增量”](example-auto-increment.html).

#### 修饰符

这[`删除`](delete.html)语句支持以下修饰符：

-   如果您指定`低优先级`修饰符，服务器延迟执行[`删除`](delete.html)直到没有其他客户端从表中读取。这仅影响仅使用表级锁定的存储引擎（例如`MyISAM`,`记忆`， 和`合并`）。

    [](<>)

-   为了`MyISAM`表，如果您使用`快的`修饰符，存储引擎在删除过程中不合并索引叶子，这可能会加快某些删除操作。

    [](<>)

-   这`忽视`修饰符导致 MySQL 在删除行的过程中忽略可忽略的错误。（在解析阶段遇到的错误以通常的方式处理。）由于使用`忽视`作为警告返回。有关详细信息，请参阅[IGNORE 对语句执行的影响](sql-mode.html#ignore-effect-on-execution).

    [](<>)

#### 删除顺序

如果[`删除`](delete.html)声明包括一个`订购方式`子句中，行将按照子句指定的顺序删除。这主要用于与`限制`.例如，以下语句查找与`在哪里`子句，按`时间戳列`，并删除第一个（最旧的）：

```
DELETE FROM somelog WHERE user = 'jcole'
ORDER BY timestamp_column LIMIT 1;
```

`订购方式`还有助于按照避免参照完整性违规所需的顺序删除行。

#### InnoDB 表

如果要从大表中删除许多行，则可能会超出锁定表大小`InnoDB`桌子。为了避免这个问题，或者只是为了尽量减少表保持锁定的时间，下面的策略（不使用[`删除`](delete.html)完全）可能会有所帮助：

1.  选择行*不是*要删除到与原表结构相同的空表中：

    ```
    INSERT INTO t_copy SELECT * FROM t WHERE ... ;
    ```

2.  采用[`重命名表`](rename-table.html)以原子方式将原始表移开并将副本重命名为原始名称：

    ```
    RENAME TABLE t TO t_old, t_copy TO t;
    ```

3.  删除原始表：

    ```
    DROP TABLE t_old;
    ```

    没有其他会话可以访问所涉及的表，而[`重命名表`](rename-table.html)执行，因此重命名操作不会出现并发问题。看[第 13.1.36 节，“重命名 TABLE 语句”](rename-table.html).

#### MyISAM 表

在`MyISAM`表，删除的行在链表中维护，随后[`插入`](insert.html)操作重用旧的行位置。要回收未使用的空间并减小文件大小，请使用[`优化表`](optimize-table.html)声明或[**迈萨姆奇克**](myisamchk.html)用于重组表的实用程序。[`优化表`](optimize-table.html)更容易使用，但是[**迈萨姆奇克**](myisamchk.html)是比较快的。看[第 13.7.3.4 节，“优化 TABLE 语句”](optimize-table.html)， 和[第 4.6.4 节，“myisamchk - MyISAM 表维护实用程序”](myisamchk.html).

这`快的`修饰符影响是否合并索引叶子以进行删除操作。`快速删除`对于删除行的索引值被稍后插入的行中的相似索引值替换的应用程序最有用。在这种情况下，删除值留下的空洞会被重用。

`快速删除`当删除的值导致跨越一系列索引值的索引块不足时，新插入再次发生时，它就没有用了。在这种情况下，使用`快的`可能会导致索引中的空间被浪费，而这些空间仍未回收。这是这种情况的一个示例：

1.  创建一个包含索引的表`自动递增`柱子。

2.  在表中插入许多行。每次插入都会产生一个索引值，该值被添加到索引的高端。

3.  使用删除列范围低端的行块`快速删除`.

    在这种情况下，与已删除索引值关联的索引块变得未满，但由于使用了`快的`.当新的插入发生时，它们仍然未满，因为新行在已删除范围内没有索引值。此外，即使您以后使用它们，它们也会保持填充不足[`删除`](delete.html)没有`快的`，除非某些已删除的索引值恰好位于未填充块内或附近的索引块中。要在这些情况下回收未使用的索引空间，请使用[`优化表`](optimize-table.html).

    如果要从表中删除许多行，使用它可能会更快`快速删除`其次是[`优化表`](optimize-table.html).这会重建索引，而不是执行许多索引块合并操作。

#### 多表删除

您可以在一个中指定多个表[`删除`](delete.html)根据条件从一个或多个表中删除行的语句`在哪里`条款。你不能使用`订购方式`要么`限制`在一个多表中`删除`.这*`表参考`*子句列出了连接中涉及的表，如中所述[第 13.2.10.2 节，“JOIN 子句”](join.html).

对于第一个多表语法，仅匹配前面列出的表中的行`从`子句被删除。对于第二种多表语法，仅匹配表中列出的行`从`子句（在`使用`条款）被删除。效果是您可以同时从多个表中删除行，并拥有仅用于搜索的附加表：

```
DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;
```

要么：

```
DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;
```

这些语句在搜索要删除的行时使用所有三个表，但仅从表中删除匹配的行`t1`和`t2`.

前面的例子使用`内部联接`, 但多表[`删除`](delete.html)语句可以使用允许的其他类型的连接[`选择`](select.html)陈述，例如`左连接`.例如，要删除存在于`t1`没有匹配的`t2`， 用一个`左连接`：

```
DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
```

语法允许`.*`每次之后*`tbl_name`*为了兼容**使用权**.

如果您使用多表[`删除`](delete.html)涉及的声明`InnoDB`对于存在外键约束的表，MySQL 优化器可能会以不同于其父/子关系的顺序处理表。在这种情况下，语句失败并回滚。相反，您应该从单个表中删除并依赖`删除时`能力`InnoDB`规定导致其他表被相应地修改。

笔记

如果为表声明别名，则在引用表时必须使用别名：

```
DELETE t1 FROM test AS t1, test2 WHERE ...
```

多表中的表别名[`删除`](delete.html)应该只在*`表参考`*声明的一部分。在其他地方，允许使用别名引用，但不允许使用别名声明。

正确的：

```
DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id=a2.id;

DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id=a2.id;
```

不正确：

```
DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2
WHERE a1.id=a2.id;

DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2
WHERE a1.id=a2.id;
```

单表也支持表别名`删除`以 MySQL 8.0.16 开头的语句。（错误 #89410，错误 #27455809）
