你或许没有用过,在一般场景下,我们对 delete 后是否需要加 limit 的问题很陌生,也不知有多大区别,今天带你来了解一下,记得mark!
写在前面,如果是清空表数据建议直接用truncate,效率上truncate远高于delete,应为truncate不走事务,不会锁表,也不会生产大量日志写入日志文件;truncate table table_name 后立刻释放磁盘空间,并重置auto_increment的值。delete删除不释放磁盘空间,但后续insert会覆盖在之前删除的数据上。详细了解请跳转另一篇博文《delete、truncate、drop的区别有哪些,该如何选择》
下面只讨论delete场景,首先,delete后面是支持limit关键字的,但仅支持单个参数,也就是[limit row_count],用于告知服务器在控制命令被返回到客户端前被删除的行的最大值。
delete limit语法如下:
(值得注意的是,当需要用到order by排序时,必须order by + limit联用,否则order by 就会被优化器优化掉,被认为无意义。)
delete [low_priority] [quick] [ignore] from tbl_name
[where ...]
[order by ...]
[limit row_count]
加limit的的优点:
以下面的这条SQL为例:
delete from t where sex = 1;
-
1. 降低写错SQL的代价,就算删错了,比如limit 500,那也就丢了500条数据,并不致命,通过binlog也可以很快恢复数据。
-
2. 避免了长事务,delete执行时MySQL会将所有涉及的行加写锁和Gap锁(间隙锁),所有DML语句执行相关行会被锁住,如果删除数量大,会直接影响相关业务无法使用。
-
3. delete数据量大时,不加limit容易把cpu打满,导致越删越慢。
针对上述第二点,前提是sex上加了索引,大家都知道,加锁都是基于索引的,如果sex字段没索引,就会扫描到主键索引上,那么就算sex = 1 的只有一条记录,也会锁表。
对于delete limit 的使用,MySQL大佬丁奇有一道题:
如果你要删除一个表里面的前 10000 行数据,有以下三种方法可以做到:
第一种,直接执行 delete from T limit 10000;
第二种,在一个连接中循环执行 20 次 delete from T limit 500;
第三种,在 20 个连接中同时执行 delete from T limit 500。
你先考虑一下,再看看几位老铁的回答:
--------------------------------------------
Tony Du:
-
方案一,事务相对较长,则占用锁的时间较长,会导致其他客户端等待资源时间较长。
-
方案二,串行化执行,将相对长的事务分成多次相对短的事务,则每次事务占用锁的时间相对较短,其他客户端在等待相应资源的时间也较短。这样的操作,同时也意味着将资源分片使用(每次执行使用不同片段的资源),可以提高并发性。
-
方案三,人为自己制造锁竞争,加剧并发量。
-
方案二相对比较好,具体还要结合实际业务场景。
--------------------------------------------
肉山:
不考虑数据表的访问并发量,单纯从这个三个方案来对比的话。
-
第一个方案,一次占用的锁时间较长,可能会导致其他客户端一直在等待资源。
-
第二个方案,分成多次占用锁,串行执行,不占有锁的间隙其他客户端可以工作,类似于现在多任务操作系统的时间分片调度,大家分片使用资源,不直接影响使用。
-
第三个方案,自己制造了锁竞争,加剧并发。
最后
这份《“java高分面试指南”-25分类227页1000+题50w+字解析》同样可分享给有需要的朋友,感兴趣的伙伴们可挑战一下自我,在不看答案解析的情况,测试测试自己的解题水平,这样也能达到事半功倍的效果!(好东西要大家一起看才香)
CodeChina开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频】
ttps://codechina.csdn.net/m0_60958482/java-p7)**
[外链图片转存中…(img-eKeUpQLk-1630547261852)]
[外链图片转存中…(img-oy8q8Zi3-1630547261854)]