MySQL的SQL语句 - 数据操作语句(2)- DELETE 语句

DELETE 语句

DELETE 是 DML 语句,用于从表中删除行。

DELETE 语句可以用 WITH 子句开头,定义在 DELETE 中可访问的公用表表达式。

单表语法

1. DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [[AS] tbl_alias]
2.     [PARTITION (partition_name [, partition_name] ...)]
3.     [WHERE where_condition]
4.     [ORDER BY ...]
5.     [LIMIT row_count]

DELETE 语句从 tbl_name 中删除行并返回删除的行数。

主要子句

可选 WHERE 子句中的条件标识要删除的行。如果没有 WHERE 子句,则删除所有行。

where_condition 是一个表达式,对于要删除的每一行,其计算结果为 true。

如果指定了 ORDER BY 子句,则按指定的顺序删除行。LIMIT 子句对可以删除的行数进行了限制。这些子句适用于单表删除,但不适用于多表删除。

多表语法

1. DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
2.     tbl_name[.*] [, tbl_name[.*]] ...
3.     FROM table_references
4.     [WHERE where_condition]
5. 
6. DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
7.     FROM tbl_name[.*] [, tbl_name[.*]] ...
8.     USING table_references
9.     [WHERE where_condition]

权限

要从表中删除行,需要对表具有 DELETE 权限。对于仅被读取的列,比如在 WHERE 子句中命名的列,只需要 SELECT 权限。

性能

当不需要知道删除的行数时,TRUNCATE TABLE 语句比不带 WHERE 子句的 DELETE 语句更快地清空表。与 DELETE 不同,TRUNCATE TABLE 不能在事务中使用,也不能在表上有锁的情况下使用。

为了确保给定的 DELETE 语句不会花费太多时间,MySQL 特有的用于 DELETE 语句的 LIMIT row_count 子句指定要删除的最大行数。如果要删除的行数大于限制,请重复执行 DELETE 语句,直到受影响的行数小于限制值。

子查询

不能在一个子查询中对同一个表进行删除和选择。

分区表支持

DELETE 支持使用 PARTITION 选项显式地选择分区,该选项获取一个或多个分区或子分区(或两者)的逗号分隔名称列表,从中选择要删除的行。未包含在列表中的分区将被忽略。给定一个分区为 p0 的分区表 t,执行 DELETE FROM t PARTITION (p0) 与执行 ALTER TABLE t TRUNCATE PARTITION (p0) 对表的影响相同;在这两种情况下,分区 p0 中的所有行都将被删除。

PARTITION 可以与 WHERE 条件一起使用,在这种情况下,只在列出的分区中的行上进行条件测试。例如,DELETE FROM t PARTITION (p0) WHERE c < 5,从分区 p0 中删除 c < 5 的行;任何其他分区中的行都不被检查,因此不受 DELETE 的影响。

PARTITION 选项也可以用于多表 DELETE 语句。在 FROM 选项中的每个表最多可以使用一个这样的选项。

自动递增列

如果删除包含 AUTO_INCREMENT 列的最大值的行,则该值不会重新用于 MyISAM 或 InnoDB 表。如果在自动提交模式下使用 DELETE FROM tbl_name(不带 WHERE 子句)删除表中的所有行,则除 InnoDB 和 MyISAM 外,所有存储引擎的序列都会重新开始。

对于 MyISAM 表,可以在多列键中指定 AUTO_INCREMENT 辅助列。在这种情况下,即使 MyISAM 表,也会重用从序列顶部删除的值。

修饰符

DELETE 语句支持以下修饰符:

● 如果指定了 LOW_PRIORITY 修饰符,服务器会延迟 DELETE 的执行,直到没有其他客户端从表中读取数据。这只会影响仅使用表级锁的存储引擎(如 MyISAM、MEMORY 和 MERGE)。

● 对于 MyISAM 表,如果使用 QUICK 修饰符,存储引擎在删除期间不会合并索引叶子,这可能会加快某些类型的删除操作。

● IGNORE 修饰符会使 MySQL 在删除行的过程中忽略错误。(解析阶段遇到的错误将按照通常的方式处理。)由于使用 IGNORE 而被忽略的错误将作为警告返回。

删除顺序

如果 DELETE 语句包含 ORDER BY 子句,则按子句指定的顺序删除行。这主要是和 LIMIT 结合起来用的。例如,下面的语句找到与 WHERE 子句匹配的行,按 timestamp_column 对它们进行排序,然后删除第一(最老的)行:

1. DELETE FROM somelog WHERE user = ‘jcole‘
2. ORDER BY timestamp_column LIMIT 1;

ORDER BY 还有助于按所需的顺序删除行,避免违反引用完整性。

InnoDB表

如果从一个大表中删除很多行,可能会超出 InnoDB 表的锁表大小。为了避免这个问题,或者只是为了最小化表保持锁定的时间,下面的策略(完全不使用 DELETE)可能会有所帮助:

1 . 选择不删除的行到与原始表结构相同的空表中:

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

2 . 使用 RENAME TABLE 以原子方式移动原始表,并将副本重命名为原始名称:

1. RENAME TABLE t TO t_old, t_copy TO t;

3 . 删除原始表:

1. DROP TABLE t_old;

在执行 RENAME TABLE 时,没有其他会话可以访问所涉及的表,因此重命名操作不受并发问题的影响。

MyISAM 表

在 MyISAM 表中,删除的行保存在链接列表中,随后的插入操作重用旧的行位置。要回收未使用的空间并减少文件大小,请使用 OPTIMIZE TABLE 语句或 myisamchk 实用程序重新组织表。OPTIMIZE TABLE 更容易使用,但 myisamchk 速度更快。

QUICK 标识符影响是否对删除操作合并索引叶。DELETE QUICK 最适用于这样的应用程序:删除的行的索引值被稍后插入的行中的类似索引值替换。在这种情况下,删除的值留下的位置将被重用。

当删除的值导致索引块不够填充时,DELETE QUICK 就没有用了,而索引块的索引值范围又会发生新的插入。在这种情况下,使用 QUICK 可能会导致索引中的空间浪费,而这些空间仍然是未回收的。下面是这样一个例子:

  1. 创建一个包含索引 AUTO_INCREMENT 列的表。

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

  3. 使用 DELETE QUICK 删除列范围低端的行块。

在这种情况下,与已删除的索引值关联的索引块将变为填充不足,但由于使用 QUICK,因此不会与其他索引块合并。当发生新的插入时,它们将保持填充不足,因为新行在已删除范围内没有索引值。而且,即使稍后使用不带 QUICK 的 DELETE 语句,它们仍保持未填充满的状态,除非某些删除的索引值恰好位于填充不足块内或其邻近的索引块中。要在这些情况下回收未使用的索引空间,请使用 OPTIMIZE TABLE。

如果要从表中删除许多行,则使用 DELETE QUICK 紧跟 OPTIMIZE TABLE 可能会更快。这将重建索引,而不是执行许多索引块合并操作。

多表删除

根据 WHERE 子句中的条件,可以在 DELETE 语句中指定多个表,从一个或多个表中删除行。不能在多表删除中使用 ORDER BY 或 LIMIT。table_references 子句列出了连接中涉及的表。

对于第一个多表语句,只从 FROM 子句之前列出的表中删除匹配的行。对于第二个多表语法,只删除 FROM 子句(在 USING 子句之前)中列出的表中的匹配行。其效果是,您可以同时从多个表中删除行,并具有仅用于搜索的其他表:

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

或:

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

这些语句在搜索要删除的行时使用三个表,但只从表t1和t2中删除匹配的行。

前面的示例使用内部联接,但是多个表 DELETE 语句可以使用 SELECT 语句中允许的其他类型的联接,比如 LEFT JOIN。举例,要删除 t1 中存在但在 t2 中不匹配的行,请使用 LEFT JOIN:

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

为了与 Access 兼容,每个 tbl_name 后都允许使用 .* 语法。

如果使用包含 InnoDB 表的多表 DELETE 语句,并且 InnoDB 表有外键约束,那么 MySQL 优化器可能会按照与父/子关系不同的顺序处理表。在本例中,语句失败并回滚。相反,应该从 InnoDB 中删除一个依赖于其他表的功能。

相反,应该从单个表中进行删除,并依赖 InnoDB 提供的 ON DELETE 功能来相应地修改其他表。

注意

如果为表声明别名,则在引用该表时必须使该别名:

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

多表 DELETE 中的表别名只能在语句的 table_references 部分声明。在其他地方,允许别名引用,但不允许别名声明。

正确:

1. DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2
2. WHERE a1.id=a2.id;
3. 
4. DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2
5. WHERE a1.id=a2.id;

错误:

1. DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2
2. WHERE a1.id=a2.id;
3. 
4. DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2
5. WHERE a1.id=a2.id;

从 MySQL 8.0.16 开始单表 DELETE 语句也支持表别名。

官方文档:
https://dev.mysql.com/doc/refman/8.0/en/delete.html

MySQL的SQL语句 - 数据操作语句(2)- DELETE 语句

上一篇:关于.NET(c#)引用Dll后,找不到命名空间的问题


下一篇:CSS 与 HTML5 响应式图片