数码生活屋
白蓝主题五 · 清爽阅读
首页  > 远程协作

不锁表创建索引方法:线上业务也能流畅运行

做远程协作项目时,数据库经常要优化查询速度,加索引是最常见的操作。但传统方式一执行 ALTER TABLE 加索引,表就被住,前端页面卡住,用户抱怨连天。尤其在多人协同的系统里,比如在线文档、实时聊天这些场景,根本没法停。

问题出在哪?

MySQL 默认的 DDL 操作会锁表,尤其是老版本。比如你给一个上千万条数据的 user_log 表加个索引,命令一跑,写入全堵住,协作功能直接瘫痪。运维同事只能挑凌晨上线,还得提前发公告,生怕背锅。

其实有更好的办法

MySQL 5.6 之后支持 Online DDL,部分操作可以不锁表。比如用 ALGORITHM=INPLACE 就能在更新索引时不阻塞 DML:

ALTER TABLE user_log ADD INDEX idx_user_id (user_id)\nALGORITHM=INPLACE, LOCK=NONE;

这里的 LOCK=NONE 明确告诉 MySQL 不要加锁。当然不是所有操作都支持,但加普通索引基本没问题。你可以先查一下当前表支持哪种算法:

EXPLAIN FORMAT=JSON ALTER TABLE user_log ADD INDEX idx_action (action);

看输出里的 "access_type" 是否为 "inplace",如果是,基本可以安全执行。

更稳的方案:pt-online-schema-change

如果用的是老版本 MySQL,或者想更保险,Percona 的 pt-osc 工具就很实用。它通过创建影子表,逐步同步数据,最后原子性替换,全程不影响原表读写。

比如要给 message 表加索引:

pt-online-schema-change \n--alter "ADD INDEX idx_conversation (conversation_id)" \nD=chat_db,t=message \n--execute

它会在后台建新表,把数据一点点拷过去,同时用触发器保持两边一致。等同步完成,再快速切换。整个过程用户完全无感,特别适合高并发的远程协作系统。

别忘了应用层的小技巧

有时候不需要立刻生效。比如你发现某个查询慢,可以先在代码里临时走主键查,再过滤,撑几天等窗口期再加索引。或者用缓存先把热点数据兜住,减轻数据库压力。

还有团队协作时,DBA 和开发最好一起看执行计划。用 EXPLAIN 分析 SQL,确认新加的索引真的会被命中,别白忙一场。

实际项目中,我们做过一次线上会议系统的日志表优化。原本一加索引,消息发送就延迟。后来改用 pt-osc,全程没收到一条报障,连监控曲线都没抖。