目录1. MySQL不同版本的区别MySQL 5.6及之前版本MySQL 5.6及之后版本(Online DDL)2. 不同索引创建方式的锁表情况创建普通二级索引(最常见场景)创建主键索引或改变主键创建全文索引或空间索引3. Online DDL的具体行为支持的Online DDL操作(通常不锁表)可能需要锁表的操作4. 查看DDL操作的锁机制查看DDL操作是否支持Online使用INPLACE和COPY算法对比5. 实际案例和最佳实践案例1:安全添加索引(推荐)案例2:大表添加索引的优化案例3:监控DD
实话实说,那个年代的MySQL在创建索引时确实会锁表。具体来说:
好消息是,从MySQL 5.6开始,情况有了根本性改善:
长期稳定更新的攒劲资源: >>>点此立即查看<<<

-- MySQL 5.6+ 通常不锁表 CREATE INDEX idx_name ON users(name);
具体锁表情况分解:
-- 这个要小心,很可能锁表,特别是表里已经有数据的情况 ALTER TABLE users ADD PRIMARY KEY (id);
-- 这类特殊索引通常还是需要锁表 CREATE FULLTEXT INDEX idx_content ON articles(content);
-- 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);
-- 查看表结构,了解支持的算法和锁类型 SHOW CREATE TABLE users\G -- 查看当前是否有锁等待 SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'LOCK WAIT'; -- 或者通过performance_schema监控元数据锁 SELECT * FROM performance_schema.metadata_locks;
-- 使用INPLACE算法(尽量减少锁表) ALTER TABLE users ADD INDEX idx_phone(phone) ALGORITHM=INPLACE; -- 使用COPY算法(这个会锁表,慎用) ALTER TABLE users ADD INDEX idx_phone(phone) ALGORITHM=COPY;
-- 1. 首先在测试环境验证 - 这是铁律 -- 2. 选择业务低峰期执行 - 凌晨2点比下午2点安全得多 -- 3. 监控进程状态 - 随时掌握执行情况 -- 使用INPLACE算法,明确指定不锁表 ALTER TABLE large_table ADD INDEX idx_create_time(create_time), ALGORITHM=INPLACE, LOCK=NONE;
-- 面对超大表,直接ALTER TABLE可能不是最佳选择 -- 这时候pt-online-schema-change工具就派上用场了 -- 使用Percona Toolkit的pt-online-schema-change pt-online-schema-change \ --alter "ADD INDEX idx_email(email)" \ D=database,t=users \ --execute
-- 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%';
-- 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;
-- 执行前先摸摸底,了解表的大小和当前负载 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';
ALTER TABLE ... ALGORITHM=INPLACE就够了pt-online-schema-change或gh-ost这些专业工具# 1. 备份表结构 - 这是基本操作 mysqldump -d your_db your_table > table_structure.sql # 2. 测试环境验证 - 不要跳过这一步 # 3. 业务低峰期执行 - 时机很重要 # 4. 监控性能影响 - 全程盯紧 # 5. 验证索引效果 - 确认投资回报
-- 错误做法:在事务中执行DDL START TRANSACTION; -- 其他DML操作... ALTER TABLE users ADD INDEX idx_name(name); -- 可能导致长时间锁表 COMMIT; -- 正确做法:单独执行DDL ALTER TABLE users ADD INDEX idx_name(name);
这个问题问得好。准确来说,Online DDL并非完全零锁表。它在开始和结束时需要获取元数据锁,虽然通常非常短暂(毫秒到秒级),但如果遇到长时间未提交的事务,就可能导致等待。所以说"基本不锁表"更准确。
-- 查看当前运行进程 SHOW PROCESSLIST; -- 或者使用sys库(MySQL 5.7+) SELECT * FROM sys.session WHERE command = 'Query';
MySQL会回滚整个操作,表结构会恢复到之前状态。不过要注意的是,虽然数据不会丢,但期间可能已经消耗了大量系统资源。
| 场景 | 是否锁表 | 建议 |
|---|---|---|
| MySQL 5.6+,添加二级索引 | 基本不锁表 | 使用ALGORITHM=INPLACE, LOCK=NONE |
| 修改主键或列类型 | 通常锁表 | 使用pt-online-schema-change |
| 大表添加索引 | 可能长时间锁表 | 使用gh-ost或分批操作 |
| 生产环境高峰期 | 尽量不操作 | 选择业务低峰期 |
最终建议可以归纳为几点:
总的来说,在大多数现代MySQL部署中(5.6+版本),只要正确使用Online DDL,完全可以在不锁表的情况下添加索引,对业务的影响可以降到极小。这才是关键所在。
到此这篇关于MySQL加索引会导致数据库锁表吗的文章就介绍到这了,更多相关mysql加索引会不会导致锁表内容请搜索脚本大全以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本大全!
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述