MySQL delete limit AND 逻辑删除优劣比较 小灰灰 2022-12-16 09:04 158阅读 0赞 原文地址:[https://blog.csdn.net/qq\_39390545/article/details/107519747][https_blog.csdn.net_qq_39390545_article_details_107519747] 在业务场景要求高的数据库中,对于单条删除和更新操作,在 delete 和 update 后面加 limit 1 绝对是个好习惯。比如,在删除执行中,第一条就命中了删除行,如果 SQL 中有 limit 1;这时就 return 了,否则还会执行完全表扫描才 return。效率不言而喻。 那么,在日常执行 delete 时,我们是否需要养成加 limit 的习惯呢?是不是一个好习惯呢? 在日常的 SQL 编写中,你写 delete 语句时是否用到过以下 SQL? delete from t where sex = 1 limit 100; 你或许没有用过,在一般场景下,我们对 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 必须要和 limit 联用,否则就会被优化掉。 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:** * 方案一,事务相对较长,则占用锁的时间较长,会导致其他客户端等待资源时间较长。 * 方案二,串行化执行,将相对长的事务分成多次相对短的事务,则每次事务占用锁的时间相对较短,其他客户端在等待相应资源的时间也较短。这样的操作,同时也意味着将资源分片使用(每次执行使用不同片段的资源),可以提高并发性。 * 方案三,人为自己制造锁竞争,加剧并发量。 * 方案二相对比较好,具体还要结合实际业务场景。 \-------------------------------------------- **肉山:** 不考虑数据表的访问并发量,单纯从这个三个方案来对比的话。 * 第一个方案,一次占用的锁时间较长,可能会导致其他客户端一直在等待资源。 * 第二个方案,分成多次占用锁,串行执行,不占有锁的间隙其他客户端可以工作,类似于现在多任务操作系统的时间分片调度,大家分片使用资源,不直接影响使用。 * 第三个方案,自己制造了锁竞争,加剧并发。 至于选哪一种方案要结合实际场景,综合考虑各个因素吧,比如表的大小,并发量,业务对此表的依赖程度等。 \------------------------------------------- **~嗡嗡:** * 1. 直接 delete 10000 可能使得执行事务时间过长 * 2. 效率慢点每次循环都是新的短事务,并且不会锁同一条记录,重复执行 DELETE 知道影响行为 0 即可 * 3. 效率虽高,但容易锁住同一条记录,发生死锁的可能性比较高 \------------------------------------------- 怎么删除表的前 10000 行。比较多的朋友都选择了第二种方式,即:在一个连接中循环执行 20 次 delete from T limit 500。确实是这样的,第二种方式是相对较好的。 第一种方式(即:直接执行 delete from T limit 10000)里面,单个语句占用时间长,锁的时间也比较长;而且大事务还会导致主从延迟。 第三种方式(即:在 20 个连接中同时执行 delete from T limit 500),会人为造成锁冲突。 这个例子对我们实践的指导意义就是,在删除数据的时候尽量加 limit。这样不仅可以控制删除数据的条数,让操作更安全,还可以减小加锁的范围。所以,在 delete 后加 limit 是个值得养成的好习惯。 \------------------------------------------- 读者笔录:当然了,目前更多的操作是逻辑删除,逻辑删除。 逻辑删除update语句: (1)有索引:执行update语句会锁行 (2)无索引:执行update语句会锁整表 详见:[https://blog.csdn.net/u013043762/article/details/80454396][https_blog.csdn.net_u013043762_article_details_80454396] \------------------------------------------- update会锁表吗? 两种情况: 1.带索引 2.不带索引 前提介绍: 方式:采用命令行的方式来模拟 1.mysq由于默认是开启自动提交事务,所以首先得查看自己当前的数据库是否开启了自动提交事务。 命令:select @@autocommit; 结果如下: \+————–+ | @@autocommit | \+————–+ | 0 | \+————–+ 如果是1,那么运行命令:set autocommit = 0;设置为不开启自动提交 2.当前的数据库表格式如下 tb\_user | CREATE TABLE `tb_user` ( `id` bigint(20) NOT NULL AUTO\_INCREMENT, `name` varchar(32) DEFAULT NULL, `phone` varchar(11) DEFAULT NULL, `operator` varchar(32) DEFAULT NULL, `gmt_create` datetime DEFAULT NULL, `gmt_modified` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO\_INCREMENT=3 DEFAULT CHARSET=utf8 显然除了主键,我没有加任何索引 实际例子: 1.没有索引 运行命令:begin;开启事务,然后运行命令:update tb\_user set phone=11 where name=”c1”;修改,先别commit事务。 再开一个窗口,直接运行命令:update tb\_user set phone=22 where name=”c2”;会发现命令卡住了,但是当前面一个事务通过commit提交了,命令就会正常运行结束,说明是被锁表了。 2.给name字段加索引 create index index\_name on tb\_user(name); 然后继续如1里面的操作,也就是一个开启事务,运行update tb\_user set phone=11 where name=”c1”;先不提交 然后另一个运行update tb\_user set phone=22 where name=”c2”;发现命令不会卡住,说明没有锁表 但是如果另一个也是update tb\_user set phone=22 where name=”c1”;更新同一行,说明是锁行了 3.总结 如果没有索引,所以update会锁表,如果加了索引,就会锁行 [https_blog.csdn.net_qq_39390545_article_details_107519747]: https://blog.csdn.net/qq_39390545/article/details/107519747 [https_blog.csdn.net_u013043762_article_details_80454396]: https://blog.csdn.net/u013043762/article/details/80454396
相关 MySQL delete limit AND 逻辑删除优劣比较 原文地址:[https://blog.csdn.net/qq\_39390545/article/details/107519747][https_blog.csdn.net_ 小灰灰/ 2022年12月16日 09:04/ 0 赞/ 159 阅读
相关 hdfs问题-删除,遍历某个目录时显示GC overhead limit exceeded 之前碰到一个问题,使用hdfs ls或者find命令时,会报GC问题,如下图 Exception in thread "main" java.lang.OutOfMe 水深无声/ 2022年12月09日 02:25/ 0 赞/ 98 阅读
相关 mysql的limit用法、逻辑分页和物理分页 参考[https://www.cnblogs.com/tonghun/p/7122801.html][https_www.cnblogs.com_tonghun_p_71228 蔚落/ 2022年05月15日 00:23/ 0 赞/ 353 阅读
相关 mysql删除超过指定条数数据(先order by,再limit) 想实现删除最近100条记录之前的所有数据。 一开始想实现的SQL如下: DELETE FROM car_base_state WHERE car_id IN ( 我就是我/ 2022年02月01日 12:13/ 0 赞/ 867 阅读
还没有评论,来说两句吧...