mysql删除慢怎么优化 mysql删除太慢( 二 )


但这过程为啥这么慢?pro?ling确实是提供给我们更多的线索了,但似乎还是没法解决问题 。但已经捕获到异常关键点 , 就是Sending Data的耗时很高!
接着:
看innodb存储引擎的一些状态,此时发现一个奇怪的指标:history list length,值特别高,达到上万 。
MVCC就是多个事务在对同一个数据 ,  有人写,有人读,此时可以有多种隔离级别,对一个数据有个多版本快照链条,才能实现MVCC和各种隔离级别 。
所以当你有大量事务执行时,就会构建这种undo多版本快照链条 , 此时history list length就会很高 。然后在事务提交后,会有一个多版本快照链条的自动purge清理机制,清理了,该值就会降低 。一般该值不应过高,所以注意到第二个线索:history list length过高,即大量的undo多版本链条数据没有清理 。推测可能有的事务长时间运行,所以其多版本快照不能被purge清理,进而导致history list length过高 。
经过这俩线索推测 , 在大量简单SQL变成慢查询时,SQL因为Sending Data环节异常,耗时过高;同时此时出现一些长事务长时间运行,大量的频繁更新数据,导致有大量undo多版本快照链条,还无法purge清理 。
因为发现有大量的更新语句在活跃,而且有那种长期活跃的长事务一直在跑而没有结束,问了下系统负责人,在后台跑了个定时任务:他居然开了一个事务,然后在一个事务里删除上千万数据,导致该事务一直在运行 。
这种长事务的运行会导致你删除时,仅只是对数据加了一个删除标记 , 事实上并没有彻底删除 。此时你若和长事务同时运行的其它事务里再查询 , 他在查询时可能会把那上千万被标记为删除的数据都扫描一遍 。因为每次扫描到一批数据,都发现标记为删除了,接着就会再继续往下扫描,所以才导致一些查询语句很慢 。
那为何你启动一个事务,在事务里查询 , 凭什么就要去扫描之前那个长事务标记为删除状态的上千万的垃圾数据?讲道理,那些数据都被删了,跟你没关系了呀,你可以不去扫描他们 嘛!
而问题症结在于,那个删除千万级数据的事务是个长事务!即当你启动新事务查询时 , 那个删除千万级数据的长事务一直在运行,它是活跃的!结合MVCC的Read View机制,当你启动一个新事务查询时 , 会生成一个Read View 。你的新事务查询时,会根据ReadView去判断哪些数据可见及可见的数据版本号,因为每个数据都有个版本链条 , 有时你能可见的仅是这个数据的一个 历史 版本 。
所以正是因为该长事务一直在运行,还在删除大量数据,而且这些数据仅是逻辑删除 , 所以此时你新开事务的查询还是会读到所有逻辑删除数据 , 也就会出现千万级的数据扫描,导致了慢查询!
所以禁止在业务高峰期运行那种删除大量数据的语句,因为这可能导致一些正常的SQL都变慢查询,因为那些SQL也许会不断扫描你标记为删除的大量数据,好不容易扫描到一批数据,结果发现是标记为删除的,于是继续扫描下去,导致慢查询!
直接kill那个正在删除千万级数据的长事务,所有SQL很快恢复正常 。此后,大量数据清理全部放在凌晨执行 , 那个时候就没什么人使用系统了,所以查询也很少 。
mysql 里 delete in 语句暴慢无比 优化十万级别查询量 志强e5 cpu 单核100% 超3分钟才能跑完 。
优化后10秒内可以跑完 。
思路 通过临时表创建索引用 空间换时间避免频繁读取原表信息
【mysql删除慢怎么优化 mysql删除太慢】

推荐阅读