暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

林员外聊编程 2020-09-04
318
DELETE 语句
 
DELETE 是 DML 语句,用于从表中删除行。
 
DELETE 语句可以用 WITH 子句开头,定义在 DELETE 中可访问的公用表表达式。
 
单表语法
 
DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name [[AS] tbl_alias]
[PARTITION (partition_name [, partition_name] ...)]
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]
 
DELETE 语句从 tbl_name 中删除行并返回删除的行数。
 
主要子句
 
可选 WHERE 子句中的条件标识要删除的行。如果没有 WHERE 子句,则删除所有行。
 
where_condition 是一个表达式,对于要删除的每一行,其计算结果为 true
 
如果指定了 ORDER BY 子句,则按指定的顺序删除行。LIMIT 子句对可以删除的行数进行了限制。这些子句适用于单表删除,但不适用于多表删除。
 
多表语法
 
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]
 
权限
 
要从表中删除行,需要对表具有 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 的执行,直到没有其他客户端从表中读取数据。这只会影响仅使用表级锁的存储引擎(MyISAMMEMORY MERGE)
 
● 对于 MyISAM 表,如果使用 QUICK 修饰符,存储引擎在删除期间不会合并索引叶子,这可能会加快某些类型的删除操作。
 
● IGNORE 修饰符会使 MySQL 在删除行的过程中忽略错误。(解析阶段遇到的错误将按照通常的方式处理。)由于使用 IGNORE 而被忽略的错误将作为警告返回。
 
删除顺序
 
如果 DELETE 语句包含 ORDER BY 子句,则按子句指定的顺序删除行。这主要是和 LIMIT 结合起来用的。例如,下面的语句找到与 WHERE 子句匹配的行,按 timestamp_column 对它们进行排序,然后删除第一(最老的):
 
DELETE FROM somelog WHERE user = 'jcole'
ORDER BY timestamp_column LIMIT 1;
 
ORDER BY 还有助于按所需的顺序删除行,避免违反引用完整性。
 
InnoDB
 
如果从一个大表中删除很多行,可能会超出 InnoDB 表的锁表大小。为了避免这个问题,或者只是为了最小化表保持锁定的时间,下面的策略(完全不使用 DELETE)可能会有所帮助:
 
1. 选择不删除的行到与原始表结构相同的空表中:
 
INSERT INTO t_copy SELECT * FROM t WHERE ... ;
 
2. 使用 RENAME TABLE 以原子方式移动原始表,并将副本重命名为原始名称:
 
RENAME TABLE t TO t_old, t_copy TO t;
 
3. 删除原始表:
 
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 LIMITtable_references 子句列出了连接中涉及的表。
 
对于第一个多表语句,只从 FROM 子句之前列出的表中删除匹配的行。对于第二个多表语法,只删除 FROM 子句(在 USING 子句之前)中列出的表中的匹配行。其效果是,您可以同时从多个表中删除行,并具有仅用于搜索的其他表:
 
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;
 
这些语句在搜索要删除的行时使用三个表,但只从表t1t2中删除匹配的行。
 
前面的示例使用内部联接,但是多个表 DELETE 语句可以使用 SELECT 语句中允许的其他类型的联接,比如 LEFT JOIN。举例,要删除 t1 中存在但在 t2 中不匹配的行,请使用 LEFT JOIN
 
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 功能来相应地修改其他表。
 
注意
 
如果为表声明别名,则在引用该表时必须使该别名:
 
DELETE t1 FROM test AS t1, test2 WHERE ...
 
多表 DELETE 中的表别名只能在语句的 table_references 部分声明。在其他地方,允许别名引用,但不允许别名声明。
 
正确:
 
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 开始单表 DELETE 语句也支持表别名。
 
 
 
 
 
 
 
 
 
 
 
 
官方文档:
https://dev.mysql.com/doc/refman/8.0/en/delete.html

文章转载自林员外聊编程,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论