答案是:可能会锁表,但取决于mysql版本、索引类型和操作方式。
1. mysql不同版本的区别
mysql 5.6及之前版本
会锁表(多数情况下)
- 创建索引时会对表加上排他锁(x锁)
- 期间表不可读写,直到索引创建完成
- 对生产环境影响较大
mysql 5.6及之后版本(online ddl)
通常不锁表,但仍有短暂锁定
- 支持online ddl(在线数据定义语言)
- 创建二级索引时,允许dml操作(insert、update、delete)
- 但开始和结束时有短暂元数据锁

2. 不同索引创建方式的锁表情况
创建普通二级索引(最常见场景)
-- mysql 5.6+ 通常不锁表 create index idx_name on users(name);
锁表情况:
- 开始阶段:获取元数据锁(mdl),非常短暂(毫秒级)
- 创建阶段:允许dml操作,不阻塞读写
- 结束阶段:再次获取元数据锁,更新表定义
创建主键索引或改变主键
-- 可能锁表,尤其是表已经有数据时 alter table users add primary key (id);
创建全文索引或空间索引
-- 通常需要锁表 create fulltext index idx_content on articles(content);
3. online ddl的具体行为
支持的online ddl操作(通常不锁表)
-- 1. 添加二级索引 alter table users add index idx_email(email); -- 2. 删除索引 alter table users drop index idx_email; -- 3. 重命名索引 alter table users rename index old_name to new_name; -- 4. 修改索引类型(如改为hash) alter table users drop index idx_email, add index idx_email using hash(email);
可能需要锁表的操作
-- 1. 修改主键 alter table users drop primary key, add primary key(new_id); -- 2. 修改列数据类型 alter table users modify column name varchar(100); -- 3. 添加自增列 alter table users add column id int auto_increment primary key; -- 4. 添加/删除外键约束 alter table orders add foreign key (user_id) references users(id);
4. 查看ddl操作的锁机制
查看ddl操作是否支持online
-- 查看支持的算法和锁类型 show create table users\g -- 查看具体的ddl操作信息 select * from information_schema.innodb_trx where trx_state = 'lock wait'; -- 或者使用performance_schema监控 select * from performance_schema.metadata_locks;
使用inplace和copy算法对比
-- 使用inplace算法(尽量减少锁表) alter table users add index idx_phone(phone) algorithm=inplace; -- 使用copy算法(会锁表) alter table users add index idx_phone(phone) algorithm=copy;
5. 实际案例和最佳实践
案例1:安全添加索引(推荐)
-- 1. 首先在测试环境验证 -- 2. 选择业务低峰期执行 -- 3. 监控进程状态 -- 使用inplace算法,指定不锁表 alter table large_table add index idx_create_time(create_time), algorithm=inplace, lock=none;
案例2:大表添加索引的优化
-- 对于超大表,可以采用pt-online-schema-change工具 -- 而不是直接执行alter table -- 使用pt-online-schema-change(percona toolkit) pt-online-schema-change \ --alter "add index idx_email(email)" \ d=database,t=users \ --execute
案例3:监控ddl执行进度
-- 在mysql 5.7+中可以监控进度
select event_name, work_completed, work_estimated,
(work_completed/work_estimated)*100 as progress_pct
from performance_schema.events_stages_current
where event_name like '%stage/innodb/alter%';6. 不同锁级别的影响
-- lock=none: 允许读写,不阻塞任何操作 alter table users add index idx_name(name) lock=none; -- lock=shared: 允许读,阻塞写 alter table users add index idx_name(name) lock=shared; -- lock=exclusive: 阻塞读写(全表锁) alter table users add index idx_name(name) lock=exclusive;
7. 生产环境最佳实践
1.评估影响
-- 先检查表大小和当前负载 select table_name, round((data_length + index_length) / 1024 / 1024, 2) as 'size(mb)', table_rows from information_schema.tables where table_schema = 'your_db' and table_name = 'your_table';
2.使用合适的工具
- 小表:直接使用
alter table ... algorithm=inplace - 大表:使用
pt-online-schema-change或gh-ost - 云数据库:使用云服务商提供的在线ddl功能
3.执行步骤
# 1. 备份表结构 mysqldump -d your_db your_table > table_structure.sql # 2. 测试环境验证 # 3. 业务低峰期执行 # 4. 监控性能影响 # 5. 验证索引效果
4.避免的陷阱
-- 错误做法:在事务中执行ddl start transaction; -- 其他dml操作... alter table users add index idx_name(name); -- 可能导致长时间锁表 commit; -- 正确做法:单独执行ddl alter table users add index idx_name(name);
8. 常见问题解答
q: online ddl真的完全不锁表吗?
a: 不完全。online ddl在开始和结束时需要获取元数据锁,虽然非常短暂(毫秒到秒级),但如果有长时间未提交的事务,可能会导致等待。
q: 如何知道ddl操作是否在执行中?
-- 查看当前运行进程 show processlist; -- 或者使用sys库(mysql 5.7+) select * from sys.session where command = 'query';
q: 添加索引失败会怎样?
a: mysql会回滚操作,表会恢复到之前状态,但期间可能消耗了大量系统资源。
9. 总结
| 场景 | 是否锁表 | 建议 |
|---|---|---|
| mysql 5.6+,添加二级索引 | 基本不锁表 | 使用algorithm=inplace, lock=none |
| 修改主键或列类型 | 通常锁表 | 使用pt-online-schema-change |
| 大表添加索引 | 可能长时间锁表 | 使用gh-ost或分批操作 |
| 生产环境高峰期 | 尽量不操作 | 选择业务低峰期 |
最终建议:
- mysql 5.6+版本:添加普通二级索引通常不锁表,可放心使用
- 主键操作或列修改:需要谨慎,可能锁表
- 超大表操作:使用专业工具(pt-online-schema-change、gh-ost)
- 生产环境:先在测试环境验证,选择合适时间执行
- 监控:执行时监控数据库性能和锁状态
在大多数现代mysql部署中(5.6+),正确使用online ddl可以实现在不锁表的情况下添加索引,对业务影响极小。
到此这篇关于mysql加索引会导致数据库锁表吗的文章就介绍到这了,更多相关mysql加索引会不会导致锁表内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论