InnoDB表快速修改字段名方案

最近被问到一个问题,InnoDB表,只修改一个字段的名字,定义不修改,是否有快速方案。

这个需求的意义来源于,在表设计初期可以预留一些字段,但在预留字段投入使用时,最好能够赋予一个有意义的名字以方便使用。

复现

以下实验基于5.1.48版本。

创建一个简单表


CREATE TABLE `t` (

`c1` int(11) DEFAULT NULL,

`c2` int(11) DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

插入10w条数据。将字段c2改名为c3.


mysql> alter table t change c2 c3 int(11) default null;

Query OK, 100000 rows affected (4.29 sec)

Records: 100000 Duplicates: 0 Warnings: 0

可以看到,虽然只是简单修改了字段名,在实验机器上耗时达到4.2s,显然重做了所有数据。由于这个表没有索引,数据量也比较小,如果对于更大数据的表,则需要更长的操作时间。

分析

我们知道,在

Innodb_file_per_table参数下,每个InnoDB表有两个文件t.frm和t.ibd. 实际上,表字段信息只保存于t.frm。这个文件保存了表的定义信息,只有8k。 仅修改字段名,实际上不需要重作数据,如果能够只对t.frm做修改,则可以加快上面这个alter语句的执行速度。

源码相关

可以想象MySQL框架中应该是调用了InnoDB引擎的某个函数,用于判断是否需要重做数据。

我们追踪一下alter table语句的执行流程,在mysql_alter_table(sql_table.cc)函数中,我们看到这个局部变量need_copy_table,它有三个可能的取值。

ALTER_TABLE_METADATA_ONLY= 0,

ALTER_TABLE_DATA_CHANGED= 1,

ALTER_TABLE_INDEX_CHANGED= 2

显然这个取值的判断结果,决定了后面的执行流程。

mysql_alter_table中调用了compare_tables用于判断alter前后的表做了多大的改动,后者在这个语句中修改了need_copy_table的值。


/* Check if changes are compatible with current handler without a copy */

if (table->file->check_if_incompatible_data(create_info, changes))

{

*need_copy_table= ALTER_TABLE_DATA_CHANGED;

DBUG_RETURN(0);

}

这个check_if_incompatitble_table的函数实现在handler/ha_innodb.cc中。这个函数的返回值可能是COMPATIBLE_DATA_NO表示表改动前后不兼容(需要重做数据)或COMPATIBLE_DATA_YES兼容(不需要重做)。

该函数有如下片段


if (check_column_being_renamed(table, NULL)) {

return COMPATIBLE_DATA_NO;

}

其实现逻辑是,如果有任何一个字段名被修改,则返回COMPATIBLE_DATA_NO。

简单修改

有了上述分析,要做到快速修改表字段名,只需要把调用check_column_being_renamed的这三行注释掉即可。重新编译发布后,执行结果如下。


mysql> alter table t change c2 c3 int(11) default null;

Query OK, 0 rows affected (0.01 sec)

Records: 0 Duplicates: 0 Warnings: 0

可以看到,这回执行基本不需要时间. 对比修改前后的t.ibd的MD5,没有修改,而t.frm中只是将c2的字段名改为c3,其他不变。

问题!!

这里的问题是,这个修改,是否会有副作用?虽然我们知道修改字段名应该是对数据时没有影响的,但MySQL就是这么实现了。

更深入的调查带来了“坏消息“。 在MySQL 5.1.45版本中,就没有这个字段名的判断,也就是说在5.1.45中仅修改字段名是只修改frm文件的。

在新版本中特别加入的判断,是否有什么原因?这是撰写本文的意图。若有与此相关的bug或者文章说明,请回复或站内私信我。

延伸

实际上,关于这个问题,还可以继续深入,这里抛砖引玉。

1) 如果上述修改有副作用,副作用是什么,是否可以通过简单修改ibd文件,仍达到快速修改的目的?

2) 在例子中我们简单试验了修改字段名。对于varchar字段,alter table将字段长度增加,是否也可以按照上述思路快速修改?因为我们知道对于还没有数据的varchar字段长度改变,并不影响聚簇索引上的数据。 如果可行,对于预留varchar字段作为扩展来说,也是很有意义实现请看下篇。

时间: 2024-10-30 10:44:23

InnoDB表快速修改字段名方案的相关文章

InnoDB表快速修改varchar字段长度方案

前一篇文章末尾提到InnoDB快速修改字段长度.其实用场景在于,在设计表时,若需要预留varchar类型字段,还无法确定实际需要的长度.而当需要启用到预留的字段时,表中可能已经有很多数据,此时要根据需要修改字段长度, 若能够不需要重做数据,则能够减少这个修改操作对线上服务的影响. 几点说明 1. 注意到这里适用的是varchar类型, char类型不在本文讨论范围内.实际上,由于varchar类型字段数据并不是直接存储在聚簇索引中,才使得快速修改成为可能.而char类型改变长度至少要将整个聚簇索

InnoDB 中文参考手册 --- 4 建立 InnoDB 表

参考|参考手册|中文 4 建立 InnoDB 表假设你已以 mysql test 命令方式运行了 MySQL 客户端程序.为了建立一个 InnoDB 格式的表你必须在 SQL 命令中指定 TYPE = InnoDB : CREATE TABLE CUSTOMER (A INT, B CHAR (20), INDEX (A)) TYPE = InnoDB; 这个 SQL 命令将在 my.cnf 中设定的 InnoDB 数据文件中创建一个表和一个列 A 的索引,同时将在 MySQL 数据目录下的 t

InnoDB 中文参考手册 --- 14 InnoDB 表的限制

参考|参考手册|中文 InnoDB 中文参考手册 --- 犬犬(心帆)翻译 14 InnoDB 表的限制 在 < 3.23.50 版本的 InnoDB 中,不可以使用 ALTER TABLE 或 CREATE INDEX 来修改一个已经有了外键约束或参考了外键约束的表.使用 DROP TABLE 和 CREATE TABLE 来代替它. 不可以将 MySQL 系统表(如 'user' 或 'host' )转换成 InnoDB 类型.系统表必须总是为 MyISAM 类型的. InnoDB 表不支持

走近VB.Net(十二) 注册表快速入门

快速入门|注册表 走近VB.Net(十二) 注册表快速入门 作者:hejianzhong VB.Net中文站(http://vbnetcn.126.com) 首先介绍一下注册表的相关基础知识:注册表的每一个文件夹被称为一个Key(项),这个文件夹的子文件夹被称为SubKey(子项),而在一个子项中有不同的Value Name(值项-即数值顶),值项后面就是你要保存的数据Value Data(数据)了.而在子项中通常都有一个Default Value 是默认的Value Name,相信打开过注册表

MySQL InnoDB表空间及日志文件简介

MySQL一个显著的特点是其可插拔的存储引擎,因此MySQL文件分为两种:一种是MySQL服务器本身的文件(主要是一 些日志文件,如错误日志.二进制日志等),所有的存储引擎共享:另一种是和具体存储引擎相关的文件.本文主要介 绍和InnoDB存储引擎相关的文件(数据+日志),至于MySQL服务器本身的日志文件,可以参考<[MySQL] 日志文件概述 >. InnoDB表空间文件 InnoDB在很多方面和Oracle非常像,它的数据也是按表空间存储的,表空间是一个在逻辑上为整体的存储块,默认情 况

MySQL数据库INNODB 表损坏修复过程

  突然收到MySQL报警,从库的数据库挂了,一直在不停的重启,打开错误日志,发现有张表坏了.innodb表损坏不能通过repair table 等修复myisam的命令操作.现在记录下解决过程,下次遇到就不会这么手忙脚乱了. 处理过程: 一遇到报警之后,直接打开错误日志,里面的信息: InnoDB: Database page corruption on disk or a failed InnoDB: file read of page 30506. InnoDB: You may have

PS快速修出完美肌肤效果教程

  不知道从何时开始,磨皮似乎已经成为PS处理人像照片的必须步骤,这篇教程给脚本之家的朋友们介绍的是不磨皮也能快速修出完美肌肤的快速处理方法,相比磨皮处理,这样的手法来的更加的真实.教程的原创作者是LynChain,感谢LynChain的原创分享! 先把效果图展示一下~ 上面的是没有修的图, 下面的是ps祛斑之后的图(我做的还不够仔细,有时间的童鞋可以做的更仔细一些) 下面开始简单介绍一下修图教程了: 1,在ps打开图片后,ctrl+j复制两层,上面一层命名提亮,下面一层命名压暗,给这两层都建立

注册表快速搞定被写保护的U盘

  U盘没有写保护开关,为什么还是被写保护了?该如何解开呢?碰到这种情况的朋友想必都非常着急,因为这样的U盘无法存读取文件,无法删除,甚至连格式化操作都不能用,用各种U盘修复程序都无效.关于U盘被写保护其实是有解决方法的,下面让我们一起来看看如何用注册表快速搞定被写保护的U盘. 一.首先我们应当要查看U盘上面的写保护开关是否打开,该开关与过去使用的软盘原理一样.如果有开关一定要将它打开. 二.查看该U盘的根目录下的文件数目是否以达到最大值,通常格式的应256个.如果没有达到256个继续看下一步.

MySQL 备份恢复单个innodb表的教程

在实际环境中,时不时需要备份恢复单个或多个表(注意:这里除非明确指定,所说的表一律指InnoDB表),而对于innodb引擎恢复单个表需要整体的恢复,xtrabackup也可以单个表恢复,只不过是用的正则过滤的,不知最新版本是否支持表空间传输特性.本文将要说说怎么移动或复制部分或全部的表到另一台服务器上,而所要用到的技术点就是transportable tablespace特性,这就意味着MySQL5.6.6以及以上版本才支持. 表空间传输特性允许表空间从一个实例移动到另一个实例上.这在以前版本