添加列时如果附加auto increment选项,则不允许并发DML操作,此操作会重建表,开销巨大。最优化选项是指定:ALGORITHM=INPLACE, LOCK=SHARED。
删除列(Dropping a column) ALTER TABLE tbl_name DROP COLUMN column_name, ALGORITHM=INPLACE, LOCK=NONE; 重命名列名(Renaming a column) ALTER TABLE tbl CHANGE old_col_name new_col_name data_type, ALGORITHM=INPLACE, LOCK=NONE;如果你的目的只是修改列名,一定要保证修改后的列的数据类型,NULL/NOT NULL等属性和原来的列一致。
该操作建议指定INPLACE方式,这样只会更新frm文件,即使修改的列名是外键。
重新排列列顺序(Reordering columns) ALTER TABLE tbl_name MODIFY COLUMN col_name column_definition FIRST, ALGORITHM=INPLACE, LOCK=NONE;该操作费力不讨好,不建议对数据量超过百万级的大表进行操作,它会对表重建。
修改列数据类型(Changing the column data type) ALTER TABLE tbl_name CHANGE c1 c1 BIGINT, ALGORITHM=COPY;修改数据类型只支持COPY方式。
修改列的默认值(Setting a column default value) ALTER TABLE tbl ALTER COLUMN col DROP DEFAULT, ALGORITHM=INPLACE, LOCK=NONE; 修改列的自增熟悉(Changing the auto-increment value) ALTER TABLE table AUTO_INCREMENT=next_value, ALGORITHM=INPLACE, LOCK=NONE;该操作用于修改下一条记录的自增值,只会修改内存中的值,而不会修改数据文件。
对于分布式系统,经常需要手动制定开始自增的值,可以使用该方法。
修改NULL/NOT NULL属性(Making a column NULL and Making a column NOT NULL) -- Making a column NULL ALTER TABLE tbl_name MODIFY COLUMN column_name data_type NULL, ALGORITHM=INPLACE, LOCK=NONE; -- Making a column NOT NULL ALTER TABLE tbl_name MODIFY COLUMN column_name data_type NOT NULL, ALGORITHM=INPLACE, LOCK=NONE;因为设置列为NULL时,该列在原有数据类型空间的基础上增加一个直接来存储是否为NULL,所以需要重建表。
当把NULL的列设为NOT NULL时,如果有记录为NULL,则该操作会失败。
修改ENUM或SET的定义(Modifying the definition of an ENUM or SET column) CREATE TABLE t1 (c1 ENUM('a', 'b', 'c')); ALTER TABLE t1 MODIFY COLUMN c1 ENUM('a', 'b', 'c', 'd'), ALGORITHM=INPLACE, LOCK=NONE;该方式用于修改一个枚举或者集合的值,对于在尾部增加枚举或者集合值的情况,如果增加之后存储空间没有变化,就可以使用IN PLACE方式。
反之如果存储空间发生变化,如从2个字节便到三个字节,或者在中间添加值,那么就需要COPY的方式。
对于那种值的个数不确定或者枚举名称变化的场景,建议使用tinyint代替ENUM或者SET来进行存储。
实际中如何执行DDL修改综合上述,可以得出常用的三种方法。
Online DDL通过执行ALTER等命令直接修改。适用的情况如下:
表中数据量较小,低于百万级别
需要MySQL5.6+以上
能够忍受长时间不提供服务的百万级表,需要一小时以内
手动修改frm文件该方式适用于不支持Online DDL的场景,只能执行Only Modifies Metadata部分的DDL修改。修改方法如下:
首先找到MySQL数据存储路径,可从进程信息中查看:
# 查找mysql进程信息 ps aux|grep mysql查到当前数据库的数据存储目录,然后cd到所看到的frm表结构文件目录,备份需要处理的frm文件。
在数据库创建一个类似的数据表,然后修改该表,再把该表的frm文件和原来的表的frm文件替换。
-- mysql中创建临时表 create table tbl_temp like tbl; -- 修改临时表 ALTER TABLE tbl ADD COLUMN `count` bigint(20) NOT NULL DEFAULT 0 COMMENT ''; -- 锁表 flush tables with write lock; -- 备份源文件 cp tbl.frm tbl.frm.bak # 替换数据结构文件frm cp tbl_temp.frm tbl.frm -- mysql移除读锁 unlock tables; -- 测试修改是否成功 select * from tbl limit 1; -- 如果出现错误,导致连接丢失等,可以回滚 flush tables with write lock; cp tbl.frm.bak tbl.frm unlock tables; 手动执行COPY方式通过复制临时表,然后修改临时表,再把原表中的数据复制到临时表中,并切换临时表和原表。
当需要对原表中数据进行额外的处理时,只能选择此方式,该方式会造成大量的磁盘IO,并且执行期间不允许写入。
对于千万级别的表,可以分批进行复制,使用一些策略来允许迁移过程中的写入。
执行修改时需要考虑的因素首先需要对执行的表数据量进行确认,如果数据量超过百万级甚至千万级,需要检查下面的事项:
当前系统内存容量充足
当前系统内存使用情况良好
当前系统CPU使用空闲
执行修改期间是否允许停止服务
是否有其他关联的数据库,保证数据一致性