MySQL加索引会不会导致数据库锁表?

答案是:可能会锁表,但取决于MySQL版本、索引类型和操作方式。

1. MySQL不同版本的区别

MySQL 5.6及之前版本

会锁表(多数情况下)

  • 创建索引时会对表加上排他锁(X锁)

  • 期间表不可读写,直到索引创建完成

  • 对生产环境影响较大

MySQL 5.6及之后版本(Online DDL)

通常不锁表,但仍有短暂锁定

  • 支持Online DDL(在线数据定义语言)

  • 创建二级索引时,允许DML操作(INSERT、UPDATE、DELETE)

  • 但开始和结束时有短暂元数据锁

2. 不同索引创建方式的锁表情况

创建普通二级索引(最常见场景)

sql 复制代码
-- MySQL 5.6+ 通常不锁表
CREATE INDEX idx_name ON users(name);

锁表情况:

  • 开始阶段:获取元数据锁(MDL),非常短暂(毫秒级)

  • 创建阶段:允许DML操作,不阻塞读写

  • 结束阶段:再次获取元数据锁,更新表定义

创建主键索引或改变主键

sql 复制代码
-- 可能锁表,尤其是表已经有数据时
ALTER TABLE users ADD PRIMARY KEY (id);

创建全文索引或空间索引

sql 复制代码
-- 通常需要锁表
CREATE FULLTEXT INDEX idx_content ON articles(content);

3. Online DDL的具体行为

支持的Online DDL操作(通常不锁表)

sql 复制代码
-- 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);

可能需要锁表的操作

sql 复制代码
-- 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

sql 复制代码
-- 查看支持的算法和锁类型
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算法对比

sql 复制代码
-- 使用INPLACE算法(尽量减少锁表)
ALTER TABLE users ADD INDEX idx_phone(phone) ALGORITHM=INPLACE;

-- 使用COPY算法(会锁表)
ALTER TABLE users ADD INDEX idx_phone(phone) ALGORITHM=COPY;

5. 实际案例和最佳实践

案例1:安全添加索引(推荐)

sql 复制代码
-- 1. 首先在测试环境验证
-- 2. 选择业务低峰期执行
-- 3. 监控进程状态

-- 使用INPLACE算法,指定不锁表
ALTER TABLE large_table 
ADD INDEX idx_create_time(create_time),
ALGORITHM=INPLACE,
LOCK=NONE;

案例2:大表添加索引的优化

sql 复制代码
-- 对于超大表,可以采用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执行进度

sql 复制代码
-- 在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. 不同锁级别的影响

sql 复制代码
-- 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. 评估影响

sql 复制代码
-- 先检查表大小和当前负载
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-changegh-ost

  • 云数据库:使用云服务商提供的在线DDL功能

3. 执行步骤

sql 复制代码
# 1. 备份表结构
mysqldump -d your_db your_table > table_structure.sql

# 2. 测试环境验证
# 3. 业务低峰期执行
# 4. 监控性能影响
# 5. 验证索引效果

4. 避免的陷阱

sql 复制代码
-- 错误做法:在事务中执行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操作是否在执行中?

sql 复制代码
-- 查看当前运行进程
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或分批操作
生产环境高峰期 尽量不操作 选择业务低峰期

最终建议:

  1. MySQL 5.6+版本:添加普通二级索引通常不锁表,可放心使用

  2. 主键操作或列修改:需要谨慎,可能锁表

  3. 超大表操作:使用专业工具(pt-online-schema-change、gh-ost)

  4. 生产环境:先在测试环境验证,选择合适时间执行

  5. 监控:执行时监控数据库性能和锁状态

在大多数现代MySQL部署中(5.6+),正确使用Online DDL可以实现在不锁表的情况下添加索引,对业务影响极小。

相关推荐
耶夫斯计3 分钟前
【SQL_agent】基于LLM实现sql助理
数据库·python·sql·语言模型
徐同保15 分钟前
使用node清空pinecones向量数据库
数据库
陈逸轩*^_^*15 分钟前
软件工程考试速通
数据库·软件工程
Lhan.zzZ19 分钟前
Qt绘制残留问题排查与修复日志
开发语言·数据库·qt
岙利岙22 分钟前
MySQL使用jemalloc作为内存分配器
数据库·mysql·jemalloc
老年DBA27 分钟前
PostgreSQL BRIN索引揭秘
数据库·postgresql
小光学长32 分钟前
基于微信小程序的评奖评优系统51r12nd0(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·微信小程序·小程序
煎蛋学姐35 分钟前
SSM校园扶助综合服务平台的设计与实现r941j(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架·校园扶助平台
ℳ₯㎕ddzོꦿ࿐37 分钟前
企业级 MySQL 8.0 物理备份实践:使用 XtraBackup 实现全量与增量自动备份
数据库·mysql
羊小猪~~41 分钟前
数据库学习笔记(十八)--事务
数据库·笔记·后端·sql·学习·mysql