大表加索引应优先使用mysql的algorithm=inplace+lock=none或postgresql的create index concurrently实现近无锁操作,辅以低峰期执行、实时监控锁等待及从库预验证等通用策略确保安全。

大表加索引时,避免长时间锁表、减少业务阻塞,核心在于绕过 DML 锁竞争和事务阻塞。MySQL 5.6+ 支持 ALGORITHM=INPLACE 和 LOCK=NONE,PostgreSQL 支持 CONCURRENTLY,这是最小化锁等待的起点。
MySQL:用 INPLACE + LOCK=NONE 实现近乎无锁建索引
只要满足条件(如非主键、非全文索引、不涉及列类型变更),MySQL 可在不重建表、不阻塞写入的前提下在线加索引:
- 语法示例:
ALTER table orders ADD INDEX idx_user_id (user_id) ALGORITHM=INPLACE, LOCK=NONE; - 必须确认执行前
select @@innodb_online_alter_log_max_size;足够(默认128MB),否则 DDL 可能退化为 copy 算法 - 通过
SHOW PROCESSLIST或performance_schema.threads观察状态,若出现copy to tmp table,说明触发了锁表降级 - 建议搭配
pt-online-schema-change做兜底:它用影子表+触发器+重放机制,彻底规避长事务锁,适合超大表或不满足 INPLACE 条件的场景
PostgreSQL:用 CREATE INDEX CONCURRENTLY 避免排他锁
该命令不会获取 access EXCLUSIVE 锁,允许 DML 并发执行,但有关键约束:
- 不能在事务块中执行(会报错),必须单独运行
- 建索引期间若发生唯一约束冲突或死锁,索引会进入
INVALID状态,需手动DROP INDEX后重试 - 首次构建完成后,建议立即
VACUUM ANALYZE 表名更新统计信息,避免查询计划劣化 - 如需加速,可提前调大
maintenance_work_mem(例如设为 2GB),显著缩短构建时间
通用策略:分阶段 + 低峰期 + 监控闭环
技术参数只是基础,真正落地要靠节奏控制和可观测性:
- 优先选业务低峰期操作(如凌晨 2–4 点),并预留 2–3 倍预估耗时作为窗口
- 建索引前查清表的活跃事务:
SELECT * FROM pg_stat_activity WHERE state = 'active' AND backend_type = 'client backend';(PG)或SELECT * FROM information_schema.INNODB_TRX;(MySQL) - 实时监控锁等待:
sys.innodb_lock_waits(MySQL)、pg_locks+pg_stat_activity(PG),发现阻塞及时 kill 长事务 - 对 TB 级表,考虑先在从库上建索引,验证性能影响后再切主库,降低风险面
不复杂但容易忽略的是:没有银弹。CONCURRENTLY 和 INPLACE 都依赖存储引擎能力和当前负载状态,务必在测试环境完整复现生产数据量与并发模型再上线。