MySQL 8.0删除少量数据耗时久(40秒)但查询快,求排查方案
这种DELETE比同条件SELECT慢几十倍的情况确实让人头疼,尤其是从5.5迁移到8.0后出现的,结合你给出的信息,咱们一步步拆解可能的原因和排查方向:
1. 执行计划差异(最核心的排查点)
虽然你的DELETE和SELECT逻辑上是同一个关联条件,但MySQL 8.0的优化器对写操作(DELETE)和读操作(SELECT)的成本估算逻辑不一样,很可能出现执行计划完全不同的情况——比如SELECT能高效利用索引,而DELETE却走了全表扫描或者低效的关联方式。
你可以分别执行这两条语句查看执行计划:
EXPLAIN DELETE s FROM storefront s LEFT JOIN MASTER m ON m.userid=s.userid WHERE m.userid IS NULL; EXPLAIN SELECT s.userid FROM storefront s LEFT JOIN MASTER m ON m.userid=s.userid WHERE m.userid IS NULL;
重点对比type(连接类型,比如ref、range、ALL)、key(使用的索引)、rows(预估扫描行数)这几个字段。如果DELETE的rows远大于SELECT,或者没用到userid相关的索引,那就是优化器选错了执行路径——毕竟MySQL 8.0的优化器和5.5差异很大,对DELETE的成本模型有调整。
2. 写操作的日志开销(虽小但可能被放大)
DELETE是写操作,需要写入redo log(保证崩溃恢复)和undo log(支持事务回滚),而SELECT只是纯读。但你只删除9行,正常来说这个开销不该这么大,除非你的日志配置有瓶颈:
- 检查
innodb_log_file_size和innodb_log_buffer_size参数:MySQL 8.0默认的日志文件大小比5.5大很多,如果迁移时沿用了5.5的小日志配置,会导致日志频繁刷盘,拖慢写操作。 - 观察磁盘IO:用
iostat工具查看DELETE执行期间的磁盘读写利用率,如果%util接近100%,说明磁盘IO是瓶颈。
3. 锁机制与事务冲突
MySQL 8.0的InnoDB锁机制比5.5更精细,但也可能因为执行计划问题导致锁定更多行,或者存在锁等待:
- 执行
SHOW ENGINE INNODB STATUS;查看事务锁信息,重点看TRANSACTIONS和LOCK WAIT部分,确认是否有其他长事务在占用锁,或者DELETE因为执行计划问题(比如全表扫描)锁定了远超9行的记录。 - 检查
innodb_lock_wait_timeout等锁相关参数,是否和5.5的配置差异过大。
4. 表统计信息过时
MySQL优化器依赖准确的表统计信息来生成最优执行计划,如果迁移后表数据有变化但统计信息没更新,优化器可能会做出错误的选择:
- 执行
ANALYZE TABLE storefront, MASTER;更新两张表的统计信息,之后再测试DELETE的耗时。
5. MySQL 8.0特性或参数的影响
8.0有些新特性对读操作友好,但对写操作没帮助,或者参数配置和5.5差异导致的问题:
- 比如
innodb_parallel_read_threads支持并行读,能加速SELECT,但DELETE不支持并行,这会放大两者的耗时差。 - 检查
binlog_format:5.5可能用的是STATEMENT格式,而8.0默认是ROW格式。虽然9行数据量小,但如果表结构复杂,ROW格式的binlog会写入更多内容,不过不至于慢这么多,可以临时改成STATEMENT测试(注意业务兼容性)。
结合你的PROFILING信息的重点提示
从你给出的PROFILING数据看,CPU_system时间(43秒)远高于CPU_user(19秒),说明大部分时间消耗在系统调用上——比如磁盘IO、锁等待这类操作系统层面的操作,所以优先排查执行计划是否导致大量IO、磁盘日志刷盘瓶颈、是否存在锁等待这几个方向。
内容的提问来源于stack exchange,提问作者Cbpro Ads




