
无为,多年 MySQL DBA 工作经验,现就职于某知名互联网公司,对 MySQL、 Redis、PostgrepSQL 等主流数据库有一定了解,拥有丰富的一线运维经验。
1 官方文档
2 ALGORITHM 选择
COPY ,是指 DDL 时,会生成(临时)新表,将原表数据逐行拷贝到新表中,在此期间会阻塞 DML; INPLACE,无需拷贝全表数据到新表,但可能还是需要 IN-PLACE 方式(原地,无需生成新的临时表)重建整表。这种情况下,在 DDL 的初始准备和最后结束两个阶段时通常需要加排他 MDL 锁(metadata lock,元数据锁),除此外,DDL 期间不会阻塞 DML; INSTANT,只需修改数据字典中的元数据,无需拷贝数据也无需重建整表,同样,也无需加排他MDL锁,原表数据也不受影响。整个DDL过程几乎是瞬间完成的,也不会阻塞DML。这个新特性是8.0.12引入。
3 各阶段详解
创建新的临时 .frm 文件; 持有排它元数据锁,禁止读写; 根据 DDL 类型确定执行方式; 更新数据字典; 分配临时日志文件准备记录 DDL 过程中的 DML 增量,日志文件大小由 innodb_online_alter_log_max_size 参数控制,设置太小可能会导致某些情况下 DDL 失败; 分配新的 ibd 文件(按需创建)。
降级 EXCLUSIVE-MDL 锁,允许读写; 扫描 old_table 的聚集索引每一条记录 rec; 遍历新表的聚集索引和二级索引,逐一处理; 根据 rec 构造对应的索引项; 将构造索引项插入 sort_buffer 块; 将 sort_buffer 块插入新的索引 #顺序插入不做 insert buffer 写; 处理 DDL 执行过程中产生的增量( 仅 rebuild 类型需要)。
升级到 EXCLUSIVE-MDL 锁,禁止读写; 重做最后 row_log 中最后一部分增量; 更新 innodb 的数据字典表; 提交事务(刷事务的 redo 日志); 修改统计信息; rename 临时 idb 文件,frm 文件; 变更完成。
4 Online DDL 限制
在 alter table 时,如果涉及到 table copy 操作,要确保 datadir 目录有足够的磁盘空间,能够放的下整张表,因为拷贝表的的操作是直接在数据目录下进行的。
添加索引无需 table copy,但要确保 tmpdir 目录足够存下索引一列的数据(如果是组合索引,当前临时排序文件一合并到原表上就会删除)。
在主从环境下,主库执行 alter 命令在完成之前是不会进入 binlog 记录事件,如果允许 dml 操作则不影响记录时间,所以期间不会导致延迟。然而,由于从库是单个 SQL Thread 按顺序应用 relay log ,轮到 ALTER 语句时直到执行完才能下一条,所以从库会在master ddl 完成后开始产生延迟。( pt-osc 可以控制延迟时间,所以这种场景下它更合适)。
在执行一个允许并发 DML 在线 ALTER TABLE 时,结束之前这个线程会应用 row_log 记录的增量修改,而这些修改是其它 thread 里产生的,所以有可能会遇到重复键值错误 ( ERROR 1062 (23000): Duplicate entry )。 涉及到 table copy 时,目前还没有机制限制暂停 ddl,或者限制 IO 阀值,在 MySQL 5.7.6 开始能够通过 performance_schema 观察 alter table 的进度。 一般来说,建议把多个 alter 语句合并在一起进行,避免多次 table rebuild 带来的消耗。但是也要注意分组,比如需要 copy table 和只需 inplace 就能完成的,应该分两个 alter 语句。 如果 DDL 执行时间很长,期间又产生了大量的 dml 操作,以至于超过了 innodb_online_alter_log_max_size 变量所指定的大小,会引起 DB_ONLINE_LOG_TOO_BIG 错误。默认为 128M,特别对于需要拷贝大表的 alter 操作,考虑临时加大该值,以此获得更大的日志缓存空间。
执行完 ALTER TABLE 之后,最好 ANALYZE TABLE tb1 去更新索引统计信息。


最后修改时间:2020-12-23 09:55:30
文章转载自悦专栏,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




