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

前一篇文章末尾提到InnoDB快速修改字段长度。其实用场景在于,在设计表时,若需要预留varchar类型字段,还无法确定实际需要的长度。而当需要启用到预留的字段时,表中可能已经有很多数据,此时要根据需要修改字段长度, 若能够不需要重做数据,则能够减少这个修改操作对线上服务的影响。

 

几点说明

1、  注意到这里适用的是varchar类型, char类型不在本文讨论范围内。实际上,由于varchar类型字段数据并不是直接存储在聚簇索引中,才使得快速修改成为可能。而char类型改变长度至少要将整个聚簇索引重做,因此不能做到“不修改数据”

2、  与前一篇文章的思路类似,我们的目的是在执行alter table语句的时候,只修改frm文件。

3、  当然实际执行alter table修改字段长度的时候,考虑到字段中可能已经有数据,因此若是长度定义变小,则必须重做数据,因为超过长度的数据要作截断,否则逻辑上就不通过了。 因此这里只适用于将长度改大的情况。 从我们的需求出发点来看,这一点问题并不大,在预留的时候设置“小一些”即可。(小是相对的,后面会说到)

4、  我们用到的语句形如 alter table t c c varchar(300) default null. 而c字段原来声明为varchar(290) default null.

 

源码分析

从前一篇文章中我们知道MySQL在compare_tables这个函数中判断当前执行的alter table语句是否需要重做数据。

在这个函数中有这么一段

 

/*

    Go through fields and check if the original ones are compatible

    with new table.

  */

   for()

   {

      …

      if (!(tmp= field->is_equal(tmp_new_field)))

      {

        *need_copy_table= ALTER_TABLE_DATA_CHANGED;

      DBUG_RETURN(0);

      }

      …

  }

 

 

for循环中对每个字段的修改作了判断,其中field->is_equal就用于判断修改前后的字段定义是否完全相同。这里field是一个基类对象,通过多态调用Field_varstring::is_equal (sql/field.cc).

 

uint Field_varstring::is_equal(Create_field *new_field)

{ 

  if (new_field->sql_type == real_type() &&

      new_field->charset == field_charset)

  {

    if (new_field->length == max_display_length())

      return IS_EQUAL_YES;

    if (new_field->length > max_display_length() &&

        ((new_field->length <= 255 && max_display_length() <= 255) ||

         (new_field->length > 255 && max_display_length() > 255)))

      return IS_EQUAL_PACK_LENGTH; // VARCHAR, longer variable length

  }return IS_EQUAL_NO;

}

 

 

 

这个函数的逻辑比较简单。 real_type()返回的是当前的字段类型(当然是varcahr),  field_charset是当前字段实用的字符集, max_display_length()返回当前定义的长度。

我们看到这个函数有三种返回值, 其中IS_EQUAL_PACK_LENGTH类似我们需要的情况,为什么说类似呢, 这个判断中要求的不仅仅是长度增大,还要求修改前后的长度定义,要么都小于255,要么都大于255。 这个深层原因给我们带来一点麻烦,后面再说。

IS_EQUAL_PACK_LENGTH这个返回值,说明框架层考虑到这种情况是可以特殊处理的,而遗憾的是InnoDB源码中没有利用这个值,我们就用这个返回值来修改一下InnoDB中的判断逻辑。

 

简单修改

为了不影响其他引擎的结果,我们只在InnoDB内部修改。我们知道check_if_incompatible_data这个函数的返回值,决定了MySQL是否重做表数据。

 

 

bool

ha_innobase::check_if_incompatible_data(

    HA_CREATE_INFO* info,

    uint        table_changes)

{

    if (table_changes != IS_EQUAL_YES) {

        return(COMPATIBLE_DATA_NO);

}

…

}

 

 

这个传入的table_changes, 是前面各种判断的异或结果(因此在我们的例句中,这里的值是IS_EQUAL_YES|IS_EQUAL_PACK_LENGTH)。

这里判断逻辑要求必须是 IS_EQUAL_YES. 按照我们的分析,修改成如下

 

 

bool

ha_innobase::check_if_incompatible_data(

    HA_CREATE_INFO* info,

    uint        table_changes)

{

     if ((table_changes == IS_EQUAL_NO) ||

        (table_changes & ~(IS_EQUAL_YES|IS_EQUAL_PACK_LENGTH) != 0))        return(COMPATIBLE_DATA_NO);

}

…

}

 

 

 

 

 

 

 

 

  说明:虽然目前只有三种返回值,但从逻辑严谨出发,还是要判断table_changes是否在(IS_EQUAL_YES|IS_EQUAL_PACK_LENGTH)所表示的位标识范围内。

 

    重新编译发布后,执行结果如下。

 

 

mysql> alter table t c c varchar(300) default null;      

Query OK, 0 rows affected (0.01 sec)

Records: 0  Duplicates: 0  Warnings: 0

 

可以看到,这回执行基本不需要时间。

 

遗留问题

细心读者一定发现我们的例子故意绕过了上面说到的255的问题,实际上如果原来定义为varchar(4), 再修改为varchar(300),按照我们的实现,还是需要重做数据的。

判断逻辑可以很简单的修改,问题是,MySQL为什么要作这个255的分界判断?

实际上,varchar字段的实际内容前有1个或2个字节表示实际内容的长度,而到底是1个字节还是2个字节,就取决于创建表或修改的时候,这个字段声明的长度。也就是说,varchar(4) 字段的实际内容前,用1个字节表示实际长度,而varchar(300)的实际内容前,用2个字节。

因此,如果只是在修改前后长度在255两侧,则必须重做数据。

 

这样造成的问题是,从我们的需求出发,要预留字段时候,就必须先估计预留的字段大概的长度(是否超过255)。

可以将所有的varcahr字段都预留超过255字节,问题并不大,只是增加了1个字节空间而已。

 

遗留问题的解决方案

 

当然这事儿也不是不能解决的,InnoDB是为了节省空间,如果我们放弃这个节省策略,对于所有的varchar,都用2个字节来保存实际长度,就没这个问题了。下篇再续。

 

再次呼唤,本文所作修改目前只作了简单的回归测试。还没有完全确认是否引入副作用,若有相关文章涉及与此相关,请回复或站内私信我。

 

MySQL表操作实战:从建表、优化到避坑指南 在关系型数据库中,表是数据存储和组织的核心单元,其设计直接决定了数据操作的效率与系统的可维护性。理解表的创建、修改与查询原理,是掌握数据库技术的关键。从技术价值看,合理的表结构设计能有效提升查询性能、保障数据一致性,并避免后期因结构不合理导致的数据迁移难题。在实际应用场景中,无论是构建用户系统、订单模块还是日志记录,都离不开对表的精细操作。本文聚焦于MySQL表的实战操作,针对常见的“建表异常”和“mysql锁表”等问题,深入解析字符集选择、存储引擎、在线DDL以及索引优化等核心环节,提供从基础到进阶的避坑 阅读详情

相关推荐

mysql批量修改(字段)列类型

MySQL存储过程,一键批量修改一个表内的多个列(字段)类型。例如从int转换成varchar

InnoDB表快速修改字段名方案

最近被问到一个问题,InnoDB表,只修改一个字段的名字,定义不修改,是否有快速方案。 这个需求的意义来源于,在表设计初期可以预留一些字段,但在预留字段投入使用时,最好能够赋予一个有意义的名字以方便使用。   复现 以下实验基于5.1.48版本。 创建一个简单表   CREATE TABLE `t` (   `c1` int(11) DEFAULT NULL,   `c...

追风刀·丁奇 211

数据清洗(Data Cleansing)

数据清洗(Data Cleansing)是指对数据进行处理和纠错,以去除或修复数据集中存在的错误、不致、不完整和冗余的数据,从而使数据更加准确、可靠和有用。数据清洗是数据处理和数据分析中一个非常重要的步骤,它可以帮助我们提高数据的质量,从而提高数据分析和机器学习的准确性和可靠性。数据清洗是一个重要的过程,它可以帮助我们提高数据的质量,从而提高数据分析和机器学习的准确性和可靠性。在实际应用中,我们可以使用一些工具和技术来实现数据清洗,例如 Pandas、NumPy 和 OpenRefine 等。通过数据清洗,

meimei169500的博客 1万+

MYSQL 数据库字段长度修改和字段添加(可选位置)

如果需要将字段添加到指定位置,只需在后面加上AFTER column_name2,像表中添加一个字段 ,并赋值默认值。修改表中某个字段长度。

小毅的代码生活记录 3404

SLAM轨迹评估神器evo实战:从GPS到TUM格式的完整转换指南(附Python代码)

本文详细介绍了如何使用evo工具将GPS数据转换为TUM格式,以便进行SLAM轨迹评估。通过Python代码实现GPS到笛卡尔坐标的精确转换,并提供了完整的处理流程和实战案例,帮助开发者轻松完成从原始GPS数据到精确轨迹评估的全过程。特别适用于ORB-SLAM等视觉SLAM算法的性能验证。

weixin_29074295的博客 294

【PT+Arduino+OneNET基础教程1】PacketTracer中MCU芯片编程教程(零基础入门)

PacketTracer软件内MCU芯片编程入门 零基础

ChloeMax_的博客 9456

MySQL-生成批量修改表字段类型及长度(具体情况具体对待)

' modify column data_date varchar(20) comment ''数据日期'';-- ,记录笔记,批量修改表字段类型及长度。

zhangting1113的博客 605

WiFi信道状态信息 基于Intel 5300的CSI Tool 安装及使用(一)

经过半个月的坎坷安装过程,连Windows系统都没装过的本人终于颤颤巍巍把CSI TOOL装好了,下面记录一下适于我所使用设备的安装过程。设备:一台THINKPAD X201,一台师兄借的华硕主板的台式机首先,如果你和我一样对linux其实一窍不通的话,建议先反复看教程里的安装代码,照猫画虎很难一步实现的,中途一定会有这或那的问题需要解决,所以该了解的基础linux指令还是要了解,起码安装过程中的那些指令可以去查一查。.........

Silver_777的博客 2万+

mysql innodb 修改_MySQL 性能优化(INNODB下修改表结构)

最近碰到一个奇怪的问题:在MySQL中修改一个大表的结构(增加一列),发现修改缓慢无比,表是用的INNODB引擎,大小大概6G的样子!按道理修改表结构应该会很快(因为CPU耗费不是很大,无非就是读就数据写入新的文件),由于执行时间超出了预期,所以该想办法解决了(要感谢我一位无所不能的伟大的同事 )分析问题:MYSQL修改表结构时,会从旧表中读取数据,然后写入临时表(和旧表在同一目录下,命名方式为#...

weixin_28909303的博客 352

2.3 MMU Notifier(上):KVM 催生的页表变化通知

探讨了MMU Notifier机制的作用及其在虚拟化等场景中的应用。当CPU页表发生变更(如munmap、页面迁移等操作)时,需要通知拥有"第二套页表"的子系统(如KVM的EPT/NPT、IOMMU、GPU等)失效其映射。MMU Notifier通过订阅-通知机制实现这一功能,核心数据结构包括mmu_notifier订阅对象和回调接口mmu_notifier_ops。当CPU页表修改时,通过mmu_notifier_range描述变更范围,调用订阅者的回调函数进行同步,确保外部MMU与CPU页表一致性。

图形/计算GPU的驱动与虚拟化技术分享园地 1038

【系列05】端侧AI:构建与部署高效的本地化AI模型 第4章:模型量化(Quantization)

量化的基本思想是减少模型中用于表示参数和激活值的比特数。在模型训练时,参数通常使用32位浮点数(FP32)进行存储,这提供了高精度,但也消耗大量的内存和计算资源。量化则将这些32位浮点数转换成低比特数表示,通常是8位整数(INT8)。量化的原理可以概括为:对浮点数范围进行校准,并将其映射到更小的整数范围内。例如,将一个FP32的权重(如-1.5到1.5)映射到INT8的范围(-128到127)。在推理过程中,模型将使用这些低精度的整数进行计算,从而大大减少了所需的计算量。量化带来的主要收益减少模型大小。

学习,输出==》再学习再输出 1217

修改mysql字段长度

批量修改mysql字段长度

qq_38013013的博客 9406

[VT虚拟化驱动]正式启动VT

文章目录前言一、vmlaunch正式开始虚拟化二、使用步骤1.引入库2.读入数据总结 前言 本章开始真正实现一个最简单的VT框架,当然,只是能跑起来一个VT驱动了,没有并包括EPT,EPT后面再讲 提示:以下是本篇文章正文内容,下面案例可供参考 一、vmlaunch正式开始虚拟化 执行VMLAUNCH指令执行后,就正式进入虚拟化了,再该指令执行之前,得先保存Guest当前的环境,执行完VMLAUNCH后,要恢复Guest的环境,让Guest就像什么都没发生一样,所以需要保存和恢复Guest的各种寄存器的值

吾无法无天的博客 3663

MySQL 扩展 VARCHAR 长度遭遇问题的总结

最近,业务反馈有个扩展VARCHAR改表需求失败多次,需要干预处理一下。经过排查分析得出,这是由于改表系统解析改表需求得出错误的改表方案导致,即这类改表可以满足快速改表操作(直接使用),理论上任务下发后能马上改完,但是工单结果是执行触发 10 秒超时,最终工单失败。原则上,VARCHAR类型的扩展是可以满足快速改表的,我们的改表工单针对这类需求也是支持的,但是实际结果与预期不符,这到底是工单系统的 Bug?还是 MySQL 的坑呢?本文就来总结一下扩展VARCHAR。

ActionTech的博客 1022

PCL CSF布料模拟算法【2026最新版】

CSF布料模拟地面滤波算法的PCL实现,博客长期更新,本文最近更新时间为:2026年10月26日。

点云侠的博客 3918

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

varchar 字段扩展问题

当前字符集类型为 UTF8MB4,由于 UTF8MB4 为四字节编码字符集,即一个字节长度可存储 63.75(255/4)个字符,所以当我们将 VARCHAR(63) 修改为 VARCHAR(64) 时,需要增加一个字节去进行数据的存储,就要通过建立临时表的方式去完成本次长度扩容,故需要花费大量时间。如果是从 < 64 的长度扩展到 >64 的长度,则不能秒级扩展,因为改变了数据库的存储结构。规则2:如果是从 < 64 的长度扩展到 >64 的长度,则不能秒级扩展。所以定期对大表做整理还是很有必要的。

青春作伴,爱情最好 726

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

关于MySQL5.7版本varchar字段宽度扩容的一些相关知识与实践

转载文章:http://blog.itpub.net/30877447/viewspace-2740189/ 关于MySQL5.7版本varchar字段宽度扩容的一些相关知识与实践 一、字段宽度的一些扩展知识 在工作中,设计业务场景时,如果设计期能明确预计到未来线上业务表行数会很多,达到千万级别以上,且可能会存在新增字段的后续操作,可以适当的设计varchar类型的预留字段(不建议但理论层面可行,请多考虑潜在的风险点),预留字段的宽度应当遵循指定区间内宽度最小的原则,相关区间和说明见下文总结: 我们根据My

leo09999的博客 3094

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

【MySQL 数据库】表的操作

本文系统讲解MySQL表的基础操作,包括创建、查看、修改和删除表。首先介绍创建表的语法,需指定字段名、数据类型等,不同存储引擎生成不同文件。通过DESC命令可查看表结构。重点讲解ALTERTABLE的5种操作:添加/修改/删除字段、重命名表和字段。最后说明DROPTABLE的删除操作及注意事项,强调数据不可恢复性。文章提供完整操作流程示例,并总结MySQL表操作四大核心命令,帮助开发者掌握90%的表结构管理需求,特别提醒ALTER操作需谨慎执行。

wuqingyigexiaoba的博客 1431

MySQL CHAR vs VARCHAR 性能实测:InnoDB 引擎下 1000 万行数据存储与查询开销对比

本文通过实测对比MySQL中CHAR和VARCHAR类型在InnoDB引擎下的性能差异,涵盖1000万行数据的存储空间、查询开销及并发表现。结果显示,VARCHAR在存储空间和全表扫描中表现更优,而CHAR在固定长度场景和高频查询中更具优势。文章提供了详细的最佳实践建议,帮助开发者在不同场景下做出合理选择。

hqmln的博客 397

mysql的建表,添加,修改,删除字段

1.mysql的基本建表语句,并实现时间自动更新。

smileLs的博客 398

mysql 字段扩容_关于MySQL5.7版本varchar字段宽度扩容的一些相关知识与实践-yh

关于MySQL5.7版本varchar字段宽度扩容的一些相关知识与实践一、字段宽度的一些扩展知识在工作中,设计业务场景时,如果设计期能明确预计到未来线上业务表行数会很多,达到千万级别以上,且可能会存在新增字段的后续操作,可以适当的设计varchar类型的预留字段(不建议但理论层面可行,请多考虑潜在的风险点),预留字段的宽度应当遵循指定区间内宽度最小的原则,相关区间和说明见下文总结:我们根据MySQ...

weixin_39682697的博客 1581

mysql修改字段长度命令_值得收藏:一份非常完整的 MySQL 规范

一、数据库命令规范二、数据库基本设计规范三、数据库字段设计规范四、索引设计规范五、常见索引列建议六、如何选择索引列的顺序七、避免建立冗余索引和重复索引八、优先考虑覆盖索引九、索引SET规范十、数据库SQL开发规范十一、数据库操作行为规范《Java 2019 超神之路》《Dubbo 实现原理与源码解析 —— 精品合集》《Spring 实现原理与源码解析 —— 精品合集》《MyBatis 实现原理与源...

weixin_39638464的博客 2393

mysql修改字段长度命令_请别再问我MySQL 高性能优化

数据库命令规范所有数据库对象名称必须使用小写字母并用下划线分割所有数据库对象名称禁止使用 MySQL 保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来)数据库对象的命名要能做到见名识意,并且最后不要超过 32 个字符临时库表必须以 tmp_为前缀并以日期为后缀,备份表必须以 bak_为前缀并以日期 (时间戳) 为后缀所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关...

weixin_39687990的博客 671

mysql 大字段_【mysql】关于InnoDB存储引擎 text blob 大字段的存储和优化

最近在数据库优化的时候,看到一些表在设计上使用了text或者blob的字段,单表的存储空间已经达到了近100G,这种情况再去改变和优化就非常难了一、简介为了清楚大字段对性能的影响,我们必须要知道innodb存储引擎的处理方式:1、一些知识点1.1 在InnoDB 1.0.x版本之前,InnoDB 存储引擎提供了Compact和Redundant(Redundant 格式是为兼容之前版本而保留...

weixin_30470929的博客 542

MYSQL-InnoDB逻辑存储结构 详解

默认情况下InnoDB有一个共享表空间ibdata1,所有数据放入这个表空间,如果开启了innodb_file_per_table(默认ON),每张表都可以放到一个单独的表空间,但只把数据、索引和Insert Buffer Bitmap放入单独表空间,其它数据,如undo信息、插入缓冲索引页、事务信息,二次写缓冲等还是放共享表空间表空间由各个段组成,数据段、索引段、回滚段等,。

2402_82958989的博客 1214
上一篇: InnoDB表快速修改字段名方案
下一篇: MySQL权限控制的设计缺陷?
iteye_621
博客等级 码龄8年 12粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值