MySQL8.0同条件UPDATE走主键索引DELETE全表扫描原因查询
核心原因主要涉及MySQL隐式类型转换规则、InnoDB半一致性读优化逻辑,以及优化器对不同DML语句的成本评估策略:
隐式类型转换前提
你写的过滤条件是where my_id=1,my_id是varchar类型,右侧是整数,触发MySQL隐式类型转换规则:字符串类型和数字比较时会将字符串转成数字再判断,所以该条件本身无法用到任何普通索引,本来就需要全量扫描行数据。UPDATE语句走主键索引的逻辑
InnoDB针对UPDATE操作默认开启了半一致性读(semi-consistent read)优化:当UPDATE扫描行时,如果判断该行不匹配WHERE条件,会提前释放该行的行锁,无需等到事务结束,大幅降低锁冲突概率。
这个优化的实现前提是按聚集索引(主键索引)的顺序扫描行:InnoDB的行数据全部存储在主键索引的叶子节点上,按主键顺序逐行扫描时,能直接拿到行数据做条件判断,不匹配就立刻释放锁,缩小锁持有范围。
你当前表只有1行数据,优化器评估全主键索引扫描和全表扫描的成本几乎一致,所以优先选择支持半一致性读的主键扫描策略,表现为执行计划的key字段显示PRIMARY,type为index(全索引扫描,本质和全表扫描差异极小)。DELETE语句走全表扫描的逻辑
DELETE操作的半一致性读触发限制更严格:DELETE是直接擦除行数据,很少出现「扫描到不匹配行需要提前放锁」的场景,MySQL优化器不会为了适配半一致性读强制选择主键扫描。
你当前表只有1行数据,优化器直接选择成本最低的全表扫描策略,表现为执行计划type为ALL,无索引使用。
如果往表中插入数千行以上数据再执行相同语句,会发现UPDATE和DELETE都会统一走全表扫描,因为此时全表扫描的成本会低于全主键索引扫描,优化器会回归常规成本评估逻辑。
内容的提问来源于stack exchange,提问作者zhangPH

