欢迎光临深圳市中国白事服务网
详情描述

MySQL加索引是否锁表取决于索引类型、存储引擎、MySQL版本和操作方式。以下是详细分析:

一、不同情况的锁表分析

1. 默认情况(MySQL 5.6之前)

ALTER TABLE users ADD INDEX idx_email (email);
  • MySQL 5.5及之前:大部分情况会锁表(COPY算法)
  • 锁表影响:阻塞所有DML操作(INSERT/UPDATE/DELETE)

2. MySQL 5.6+ 在线DDL

ALTER TABLE users ADD INDEX idx_email (email), ALGORITHM=INPLACE, LOCK=NONE;
  • ALGORITHM=INPLACE:原地重建,不复制整表
  • LOCK=NONE:允许并发读写
  • 实际影响:仅在创建索引的最后阶段有短暂的元数据锁

3. 存储引擎差异

  • InnoDB:支持在线DDL(5.6+)
  • MyISAM:总是锁表(不支持在线DDL)

二、索引操作的锁机制

1. 在线创建索引(推荐)

-- MySQL 5.6+ 自动使用在线DDL
ALTER TABLE users ADD INDEX idx_name (name);

-- 显式指定
ALTER TABLE users ADD INDEX idx_name (name),
ALGORITHM=INPLACE,    -- 原地操作
LOCK=NONE;            -- 不锁表

2. 不同算法的锁影响

算法 锁级别 性能影响 磁盘使用
COPY 表级锁 高(阻塞DML) 高(两倍空间)
INPLACE 元数据锁(短暂)
INSTANT (8.0) 元数据锁

三、实际执行建议

1. 检查支持的DDL类型

-- 查看操作是否支持在线
SELECT * FROM INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX;
-- 或使用
SHOW ENGINE INNODB STATUS;

2. 生产环境最佳实践

# 1. 使用pt-online-schema-change(第三方工具)
pt-online-schema-change \
  --alter "ADD INDEX idx_email (email)" \
  D=database,t=users \
  --execute

# 2. 分阶段操作(大表)
-- 先创建无数据的索引
CREATE INDEX idx_partial ON users(email) WHERE id > 1000000;
-- 再逐步更新

3. 规避锁表风险

-- 在低峰期执行
SET SESSION lock_wait_timeout = 300;
SET SESSION innodb_lock_wait_timeout = 300;

-- 使用INSTANT算法(MySQL 8.0+)
ALTER TABLE users 
ADD INDEX idx_email (email),
ALGORITHM=INSTANT;

四、特殊情况会锁表

即使使用在线DDL,以下情况仍可能锁表:

添加全文索引/FULLTEXT 空间索引/SPATIAL 主键索引变更 表有外键约束且需要检查时 字段类型变更+加索引组合操作

五、监控和回滚方案

-- 监控DDL进度(MySQL 5.7+)
SELECT * FROM performance_schema.events_stages_current
WHERE EVENT_NAME LIKE '%stage/innodb/alter%';

-- 设置超时防止长时间锁表
SET SESSION innodb_lock_wait_timeout = 30;
SET SESSION lock_wait_timeout = 30;

总结建议

MySQL 5.6+:默认支持在线加索引,但显式指定ALGORITHM=INPLACE, LOCK=NONE更安全 大表操作:使用pt-online-schema-change或gh-ost MySQL 8.0+:优先使用ALGORITHM=INSTANT 始终先在测试环境验证:使用相同数据量测试 有备份才操作:避免不可逆问题

最佳实践:对大表(>1GB)的索引操作,建议在维护窗口进行,并使用专业工具监控进度和影响。