MySQL 5.7中全文索引本身不参与行级锁,所谓“全文索引导致锁冲突”实为误判;真正原因是MATCH...AGAINST不满足条件时退化为全表扫描,进而对所有扫描行加next-key锁,或混用非索引字段引发多条件锁膨胀。

MySQL 5.7 中全文索引(FULLTEXT)本身不参与行级锁机制,因此它不会直接引发事务锁冲突;所谓“全文索引导致的锁冲突”,实际是误判——真正冲突源通常是隐式全表扫描、缺失辅助索引、或在 MATCH ... AGAINST 查询中混用了非SARGable条件。
为什么 FULLTEXT 查询会触发大量锁?
FULLTEXT 索引在 MySQL 5.7 中仅支持 MATCH ... AGAINST 语法,且必须满足:查询必须是独立的 WHERE 条件(不能嵌套在 OR/AND 复合逻辑中)、不能对列做函数处理、不能用于非布尔模式下的模糊前缀(如 AGAINST('my*' IN NATURAL LANGUAGE MODE) 无效)。一旦不满足,优化器会退化为全表扫描 + 内存临时表过滤,此时:
- 所有被扫描的行在当前读(如
UPDATE ... WHERE MATCH)下都会被加next-key lock - 若 WHERE 中还混有其他非全文条件(如
AND status = 'active'),而status无索引,就会触发 index merge 或松散索引扫描,导致多把锁并发申请 -
INSERT ... SELECT ... MATCH类语句在 RR 隔离级别下,可能因间隙锁范围扩大而阻塞并发 INSERT
如何确认锁冲突真由 FULLTEXT 引起?
别急着改索引。先验证是否真是全文操作在锁表:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 查
INFORMATION_SCHEMA.INNODB_TRX,看trx_query字段是否含MATCH或AGAINST—— 若没有,说明锁来自别的语句,全文只是“背锅” - 用
SHOW ENGINE INNODB STATUS\G查LATEST DETECTED DEADLOCK段,观察锁等待链中涉及的索引名:若出现FTS_DOC_ID_INDEX或ft_*开头的索引,才说明 FULLTEXT 内部结构被卷入;但 5.7 中该索引只用于文档 ID 映射,极少成为争用点 - 重点检查
trx_state = 'LOCK WAIT'的事务,其trx_mysql_thread_id对应的PROCESSLIST中INFO是否显示长时间卡在Copying to tmp table或Sending data—— 这才是全文查询退化的真实信号
FULLTEXT 查询中哪些写法会放大锁范围?
以下写法在 5.7 中极易引发意外锁升级或扫描膨胀:
-
SELECT * FROM articles WHERE MATCH(title, content) AGAINST('+mysql -database' IN BOOLEAN MODE) AND created_at > '2025-01-01';→ 若created_at无索引,优化器放弃 FULLTEXT 索引,改走created_at全表扫描,全文条件沦为后期过滤 -
UPDATE articles SET weight = weight + 1 WHERE MATCH(title) AGAINST('optimization');→ 在 RR 下会对所有匹配文档的主键范围加 next-key lock,若匹配数万行,等于锁住大片主键区间 -
SELECT id FROM articles WHERE MATCH(title) AGAINST('api') ORDER BY id DESC LIMIT 100;→ 5.7 不支持 FULLTEXT + ORDER BY 的高效合并排序,会先取全部匹配 ID 到内存再排序,期间持有所有匹配行的 S 锁
真正有效的缓解手段
全文不是锁源,但它是放大器。解法要落在“减少扫描量”和“隔离锁粒度”上:
- 给高频组合条件建联合索引,例如
(status, FTS_DOC_ID),让非全文过滤先完成,再进 FULLTEXT 精筛 - 避免在事务中执行全文查询;把
MATCH ... AGAINST结果缓存为 ID 列表,再用WHERE id IN (...)分批更新,锁只落在目标行 - 确认是否真的需要自然语言模式:布尔模式(
IN BOOLEAN MODE)响应更快、锁更少;若只是关键词命中,禁用相关性排序(去掉ORDER BY MATCH(...) DESC) - 不要在唯一约束字段上建 FULLTEXT 索引——MySQL 5.7 不允许,但有人误建后触发元数据锁等待,表现为“锁住整个表”
最容易被忽略的一点:OPTIMIZE TABLE 重建全文索引时会持表级 S 锁,若在业务高峰期执行,所有 DML 都会被堵住;务必在低峰期做,且提前确认 innodb_ft_num_word_optimize 设置合理(默认 2000,值越小锁持续时间越短)。

















