【StoneDB】修改字段长度调研
一、调研
1.支持情况调研
以varchar数据类型为例,开启调研。
1)其他引擎/数据库调研
对象 | 字段长度修改支持情况 | 详情 |
---|---|---|
mysql-innodb | 支持 | 严格模式:可以改大;可以改小,但不能修改小于已有数据的长度;非严格模式:可以改大;可以改小,会丢失精确度 |
mysql-myisam | 支持 | 严格模式:可以改大;可以改小,但不能修改小于已有数据的长度;非严格模式:可以改大;可以改小,会丢失精确度 |
mariadb-columnstore | 不支持 | 会报错 |
ClickHouse | 不支持 | 有String类型,自动扩展,无需支持 |
TiDB | 支持 | 只支持改大,不支持改小 |
验证过程:
innodb:myisam:mariadb-columnstore:
2)字段长度范围限制
varchar的长度范围与字符集有关;例如:
字符集 | 长度范围 |
---|---|
latin1字符集 | 0~65532 |
utf8mb4字符集 | 0~16383 |
utf8字符集 | 0~21844 |
验证过程:
2.alter table语法调研
1)支持功能
主要包括以下功能:
- 索引的增加、删除
- 列的增加、删除
- 列的属性修改:类型修改、长度修改、重命名等
- 引擎修改
- 表重命名
等
2)并发控制
通过锁来进行控制并发,支持以下锁:LOCK= DEFAULT | NONE | SHARED | EXCLUSIVE
DEFAULT:默认方式,MySQL自行判断使用哪种LOCK模式,尽量不锁表。
NONE:无锁:允许Online DDL期间进行并发读写操作。如果Online DDL操作不支持对表的继续写入,则DDL操作失败,对表修改无效。
SHARED:共享锁:Online DDL操作期间堵塞写入,不影响读取。
EXCLUSIVE:排它锁:Online DDL操作期间不允许对锁表进行任何操作。
3)算法支持
支持两种算法,8.0后新增了一种算法:INSTANT。ALGORITHM=COPYALGORITHM=INPLACE
- copy 这个操作一行一行的copy数据从原始表到新表, 而且不支持并发DML,但是并发查询仍然是支持的,默认使用共享锁(可以并发查询),也可指定排他锁(并发查询和DML都不支持)。
- inplace 这个操作会避免copy表数据,但是可能会重建表。在数据准备和执行阶段会进行行锁定,通常支持并发DML。
mysql默认选择inplace,如果存储引擎不支持,就会选中copy。使用INPLACE的算法场景包括:
- alter table的操作被InnoDB online DDL的特性所支持。
- 重命名表。 mysql会重命名table对应的文件,并不会做copy数据的操作。(per_file_on_table 需要打开)
- 仅修改表的元数据的操作。包括: rename column,变更列的默认值,不改变数据类型存储空间的操作。
- 重命名索引。
- 添加或者删除一个二级索引。
4)总体支持情况
执行操作 | 允许ALGORITHM=INPLACE | 是否拷贝表 | 允许并发DML | 允许并发查询 | 备注和注意事项 |
---|---|---|---|---|---|
create index add index | Yes* | No* | Yes | Yes | 对于全文索引,有一些限制,具体看下一行。目前,该操作不是在原地执行,需要拷贝表。 |
add fulltext index | Yes | No* | No | Yes | 创建第一个全文索引涉及到拷贝表,除非有使用FTS_DOC_ID列。后面的全文索引则在原地执行。 |
drop index | Yes | No | Yes | Yes | |
optimize table | Yes | Yes | Yes | Yes | 在MySQL5.6.17里使用 ALGORITHM=INPLACE。如果设置old_alter_table=1或使用mysqld --skip-new选项,则使用 ALGORITHM=COPY。如果表使用了全文索引,则 ALGORITHM=INPLACE不适用 |
set default value for column | Yes | No | Yes | Yes | 修改.frm文件,不涉及数据文件 |
change auto-increment value | Yes | No | Yes | Yes | 修改存储到内存的一个值,不修改数据文件 |
add foreign key constraint | Yes* | No* | Yes | Yes | 禁用foreign_key_checks,则可以避免拷贝表 |
drop forgien key constraing | Yes | No | Yes | Yes | foreign_key_checks可以禁用或开启 |
rename column | Yes* | No* | Yes* | Yes | 允许并发DML,保持相同的数据类型,仅改变字段名 |
add column | Yes | Yes | Yes* | Yes | 增加auto-increment字段时不允许DML操作。虽然ALGORITHM=INPLACE可以允许,但是数据要重组,代价比较昂贵. |
drop column | Yes | Yes | Yes | Yes | 虽然ALGORITHM=INPLACE可以允许,但是数据要重组,代价比较昂贵. |
reorder columns | Yes | Yes | Yes | Yes | 虽然ALGORITHM=INPLACE可以允许,但是数据要重组,代价比较昂贵. |
change ROW_FORMAT property | Yes | Yes | Yes | Yes | 虽然ALGORITHM=INPLACE可以允许,但是数据要重组,代价比较昂贵. |
change KEY_BLOCK_SIZE property | Yes | Yes | Yes | Yes | 虽然ALGORITHM=INPLACE可以允许,但是数据要重组,代价比较昂贵. |
make column null | Yes | Yes | Yes | Yes | 虽然ALGORITHM=INPLACE可以允许, |
make cplumn not null | Yes* | Yes | Yes | Yes | 当SQL_MODE为strict_all_tables,如果执行的列包含null,则会执行失败。虽然ALGORITHM=INPLACE可以允许,但是数据要重组,代价比较昂贵. |
change data type of column | No | Yes | Yes | Yes | |
add primary key | Yes* | Yes | Yes | Yes | 虽然ALGORITHM=INPLACE可以允许,但是数据要重组,代价比较昂贵。如果列必须转换为非空的条件下,ALGORITHM=INPLACE是不允许的。 |
drop primary key and add other | Yes | Yes | Yes | Yes | 当在同一个alter table新增主键时ALGORITHM=INPLACE是允许的.数据要重组,因此代价比较昂贵。 |
drop primary key | No | Yes | No | Yes | 删除主键但是又不新增主键是被限制的 |
convert character set | No | Yes | No | Yes | 如果新的字符编码不同将会重建表 |
specify character set | No | Yes | No | Yes | 如果新的字符编码不同将会重建表 |
rebulid with force option | Yes | Yes | Yes | Yes | 在MySQL5.6.17里使用 ALGORITHM=INPLACE。如果设置old_alter_table=1或使用mysqld --skip-new选项,则使用 ALGORITHM=COPY。如果表使用了全文索引,则 ALGORITHM=INPLACE不适用 |
rebulid with "null" alter table ... engine=innodb | Yes | Yes | Yes | Yes | 在MySQL5.6.17里使用 ALGORITHM=INPLACE。如果设置old_alter_table=1或使用mysqld --skip-new选项,则使用 ALGORITHM=COPY。如果表使用了全文索引,则 ALGORITHM=INPLACE不适用 |
二、方案总结
1.alter table执行流程
经过前期调研和代码分析,修改字段长度总体实现流程如下:函数整体调用流程如下:
主要功能实现集中在mysql_alter_table函数中,具体执行流程如下:主要功能介绍和对应接口如下:1.打开表:
open_tables(thd, &table_list, &tables_opened, 0,&alter_prelocking_strategy);
2.检查引擎是否支持,修改后的表的数据类型:
check_engine
3.检查引擎是否支持alter操作:
ha_check_storage_engine_flag
4.alter table 预处理:包括列属性的赋值、新列的添加、列的删除等,其中会调用到引擎的update_create_info函数,用于赋值一些创建表的信息,stonedb引擎的此函数为空:
mysql_prepare_alter_table
5.算法选择判断每个引擎是否支持inplace算法进行alter table:
check_if_supported_inplace_alter
如果支持inplace算法进行alter table处理:
通过mysql_inplace_alter_table调用引擎的
prepare_inplace_alter_table
inplace_alter_table
commit_inplace_alter_table
这三个接口进行处理
如果不支持则采用copy算法,创建新表->复制数据>新表旧表重命名>删除旧表,达到alter table目的:
ha_create_table --创建表
copy_data_between_tables --复制数据
mysql_rename_table --重命名表
quick_rm_table --删除表
2.修改方案
1)修改引擎代码,使其走copy算法。2)update_create_info函数,需要实现,用于更新创建新表时候的一些信息。3)inplace算法需要修改,增加功能,使其支持索引的增加和删除等其他操作。涉及修改的函数,包括以下函数:
check_if_supported_inplace_alter
check_if_incompatible_data
prepare_inplace_alter_table
inplace_alter_table
commit_inplace_alter_table
转载自:https://segmentfault.com/a/1190000042276938