在 MySQL 5.6 或更高版本(强烈推荐)的 InnoDB 引擎表上,为 60 万条数据的表添加一个普通二级索引,在程序正常进行增删改查(DML 操作)的情况下:
一、关于锁表(阻塞 DML 操作):
-
通常不会导致锁表(阻塞 INSERT/UPDATE/DELETE/SELECT)。
-
原因: 现代 MySQL(5.6+)的 InnoDB 支持 Online DDL。添加二级索引默认(或显式指定 ALGORITHM=INPLACE, LOCK=NONE) 会使用在线操作方式。
-
关键特性:
ALGORITHM=INPLACE: 无需重建整个表,效率更高。LOCK=NONE: 目标是在索引构建过程中允许并发的 DML 操作(SELECT, INSERT, UPDATE, DELETE)。 你的应用程序在加索引期间可以继续正常读写该表。
-
⚠️ 重要注意事项(非完全锁表,但需警惕):
短暂元数据锁(MDL):
Online DDL 在操作的开始(准备阶段)和结束(提交阶段) 需要获取短 暂的排他元数据锁(MDL) 来更新表的定义。这个锁通常瞬间完成。阻塞风险:
如果在获取这个短暂的 MDL 锁时:存在未提交的长事务(例如,一个运行了很久的 SELECT * FROM your_table 或未提交的写操作)。
存在其他并发 DDL 操作(如另一个 ALTER TABLE)。
那么,Online DDL 操作会等待这些事务释放它们持有的 MDL 锁。这可能导致:
加索引操作本身被阻塞延迟。 在这个等待 MDL 锁期间,后续所有尝试访问该表的查询(甚至 SELECT)都可能被阻塞,看起来像是“锁表”。这是 Online DDL 操作期间影响业务的主要风险来源,而不是索引创建过程本身。
二、关于所需时间:
-
没有固定答案,取决于关键因素:
💽 磁盘速度(最大瓶颈): SSD 比 HDD 快得多。在良好 SSD 上可能只需 10 秒到 2 分钟。在 HDD 上可能需要 1 分钟到 10 分钟甚至更长。🖥️ 服务器负载: 如果服务器 CPU、内存、IO 在操作期间已经很繁忙,加索引会变慢,也可能因资源争用间接影响业务性能(即使不锁表)。
📁 索引字段大小: 索引的列越多、列类型越大(如很长的 VARCHAR, TEXT),时间越长。
⚙️ MySQL 配置: innodb_buffer_pool_size (缓存池大小), innodb_sort_buffer_size (排序缓冲区) 等参数影响排序和写入效率。
📶 并发 DML 强度: 在索引构建过程中,如果有非常高频的写操作(INSERT/UPDATE/DELETE),InnoDB 需要应用这些变更到正在构建的索引上,可能会稍微增加构建时间。
-
大致范围(经验估计,以 SSD 为主):
理想情况(SSD,普通字段,负载正常): 10 秒 - 2 分钟 较为常见。
一般情况(SSD/混合,或稍复杂字段): 30 秒 - 5 分钟。
较慢情况(HDD,大字段,高负载): 几分钟到十几分钟。
三、📌 总结与最佳实践:
- 不会锁表(阻塞 DML): 在 MySQL 5.6+ & InnoDB 上,使用 Online DDL (ALGORITHM=INPLACE, LOCK=NONE),程序正常的增删改查通常可以不受阻塞地继续进行。
- 时间较短(SSD): 在 配置良好的 SSD 服务器 上,60 万数据加一个普通索引,时间通常在 10 秒到 2 分钟左右。HDD 明显更慢。
- 最大风险是 MDL 锁等待: 操作前务必检查并避免长事务!使用 SHOW PROCESSLIST; 或查询 information_schema.innodb_trx 查看是否有长时间运行的事务。一个长事务就能阻塞整个 Online DDL 的开始或结束,导致连锁阻塞。
- 明确指定 Online DDL (强烈推荐):
sql
ALTER TABLE your_table_name ADD INDEX index_name (column_name) ALGORITHM=INPLACE, LOCK=NONE;
如果 MySQL 不支持这种无锁方式,执行会报错,而不是偷偷执行锁表操作,更安全。
- 选择业务低峰期: 即使不锁表,加索引是 IO/CPU 密集型操作,在低峰期进行可最大限度减少对整体性能的潜在影响。
- 提前在测试环境验证: 在类似硬件和数据量的测试库上模拟操作,实测耗时并观察对模拟业务的影响。
- 监控: 操作时监控数据库负载(CPU, IO, 连接数)、慢查询日志,以及操作本身的进展(MySQL 5.7+ 可通过 performance_schema 查看)。
结论: 只要满足条件(MySQL 5.6+, InnoDB, 使用 ALGORITHM=INPLACE, LOCK=NONE),在程序正常增删改查时给 60 万数据的表加索引,通常不会锁表阻塞业务,且耗时相对较短(SSD 环境下多在 2 分钟内)。成功的关键在于操作前彻底排查并终止任何可能阻塞 MDL 锁的长事务,并在低峰期操作。
(亲手操作执行60万数据量的表,增加三个字段的联合索引,服务正常运行的情况下,用时5秒)
ALTER TABLE `pzhframe_base_organization`.`biz_hr_user_info` ADD INDEX `basic_id`(`basic_id`, `isdelete`, `tenant_id`) USING BTREE ,ALGORITHM=INPLACE, LOCK=NONE ;