您当前的位置:首页 > 电脑百科 > 数据库 > MYSQL

MySQL:BUG导致DDL语句无谓的索引重建

时间:2024-03-26 11:36:07  来源:微信公众号  作者:MySQL学习
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。

一、问题模拟

使用5.7.22版本:

建表语句,注意这里字段a包含了一个索引,这是触发这个BUG的必要条件:
MySQL> show create table testmy G
*************************** 1. row ***************************
       Table: testmy
Create Table: CREATE TABLE `testmy` (
  `id` int(11) DEFAULT NULL,
  `a` varchar(24) DEFAULT NULL COMMENT 'test1',
  KEY `a` (`a`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4

数据量:
mysql> select count(*) from testmy;
+----------+
| count(*) |
+----------+
|   262144 |
+----------+
1 row in set (5.17 sec)

执行DDL语句:
alter table testmy modify `a` varchar(30) comment 'test1111';

本DDL语句主要完成:

  • 扩展varchar从24*4到30*4
  • 更改字段的comment

按照常理来讲这个DDL是只修改元数据的,因此应该瞬间完成,但是实际在5.7.22版本中这个语句重建了索引a,耗时如下:

mysql> alter table testmy modify `a` varchar(30) comment 'test1';
Query OK, 0 rows affected (2.50 sec)
Records: 0  Duplicates: 0  Warnings: 0

很明显重建了索引,才会有这么高的耗时。而在5.7的新版本或者8.0中测试这个语句是瞬间完成的。

二、官方文档说明

也就是说正常的扩展varchar的长度,只要字符集字节数量*字符数量不跨越256,那么就是修改元数据,不会重建索引。

三、问题分析

既然不符合官方文档的说明,那么这个问题肯定是某种BUG导致。当我们进行DDL操作的时候,需要对比更改部分和现有的数据字典中标定义的差别,然后根据这些差别来定义操作方式,然后根据操作方式来判断哪一种DDL 方式比较合适,关于定义操作方式的部分来自于函数fill_alter_inplace_info,而在函数中会根据新表的索引和老表的索引字段的长度判断是否需要drop索引和新建索引,代码中体现为如下:

  /*
    Step through all keys of the old table and search matching new keys.
  */
  for (table_key= table->key_info; table_key < table_key_end; table_key++) //循环老表的索引
  {
    /* Skip renamed keys. */
    if (table_key->flags & HA_KEY_RENAMED)
      continue;

    new_key= find_key_cs(table_key->name, ha_alter_info->key_info_buffer,
                         new_key_end);//在新的定义中是否包含这个索引

    if (new_key == NULL) //如果找不到说明这个索引要drop掉
    {
      /* Matching new key not found. This means the key should be dropped. */
      ha_alter_info->add_dropped_key(table_key); //加入到drop key buffer
    }
    else if (has_index_def_changed(ha_alter_info, table_key, new_key))//是否索引有所改变
    {
      /* Key was modified. */
      ha_alter_info->add_modified_key(table_key, new_key); //加入到modify key buffer
    }
  }

而加入到modify buffer后这个索引就是需要drop并且add的,因此DDL类型定义为,Alter_inplace_info::DROP_INDEX|Alter_inplace_info::ADD_INDEX,因此就需要进行索引的删除和重建,因此关键就是函数has_index_def_changed的更改,我们先看5.7.22的这个BUG相关的判断点:

    if (key_part->length != new_part->length)
      return true;  

也就是当索引字段长度更改了就返回true。而在新版本中:

    if (key_part->length != new_part->length &&
        ha_alter_info->alter_info->flags == Alter_info::ALTER_CHANGE_COLUMN &&
        (key_part->field->is_equal((Create_field *)new_field) == IS_EQUAL_PACK_LENGTH))
    {
      ha_alter_info->handler_flags|=
          Alter_inplace_info::ALTER_COLUMN_INDEX_LENGTH;
    }
    else if (key_part->length != new_part->length)
      return true;

变更还是比较大的,主要是key_part->field->is_equal((Create_field *)new_field) == IS_EQUAL_PACK_LENGTH)这个条件是否满足,而判定的函数为Field_varstring::is_equal,

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;
    DBUG_ASSERT(0 == (new_field->length % field_charset->mbmaxlen));
    DBUG_ASSERT(0 == (max_display_length() % field_charset->mbmaxlen));
    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;
}

其重点为如下:

  • A:如果新的字段长度>老的字段的长度
  • B:字段长度不能跨越255字节

那么则返回IS_EQUAL_PACK_LENGTH,因此就这个点上has_index_def_changed函数就会返回false,不会删除和重建索引了。

四、相关BUG

这个BUG虽然有点老了,是5.7.23修复的,如下:

但是对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障,因此还是建议任何DDL操作除了翻看官方文档以外,都需要在相同版本的数据库测试环境测试其耗时是否达到预估水平。



Tags:MySQL   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  Search: MySQL  点击:(5)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  Search: MySQL  点击:(10)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  Search: MySQL  点击:(8)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  Search: MySQL  点击:(23)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10  Search: MySQL  点击:(5)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  Search: MySQL  点击:(26)  评论:(0)  加入收藏
MySQL数据恢复,你会吗?
今天分享一下binlog2sql,它是一款比较常用的数据恢复工具,可以通过它从MySQL binlog解析出你要的SQL,并根据不同选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。主要...【详细内容】
2024-02-22  Search: MySQL  点击:(41)  评论:(0)  加入收藏
如何在MySQL中实现数据的版本管理和回滚操作?
实现数据的版本管理和回滚操作在MySQL中可以通过以下几种方式实现,包括使用事务、备份恢复、日志和版本控制工具等。下面将详细介绍这些方法。1.使用事务:MySQL支持事务操作,可...【详细内容】
2024-02-20  Search: MySQL  点击:(50)  评论:(0)  加入收藏
为什么高性能场景选用Postgres SQL 而不是 MySQL
一、 数据库简介 TLDR;1.1 MySQL MySQL声称自己是最流行的开源数据库,它属于最流行的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件之一。LAMP...【详细内容】
2024-02-19  Search: MySQL  点击:(36)  评论:(0)  加入收藏
MySQL数据库如何生成分组排序的序号
经常进行数据分析的小伙伴经常会需要生成序号或进行数据分组排序并生成序号。在MySQL8.0中可以使用窗口函数来实现,可以参考历史文章有了这些函数,统计分析事半功倍进行了解。...【详细内容】
2024-01-30  Search: MySQL  点击:(53)  评论:(0)  加入收藏
▌简易百科推荐
MySQL 核心模块揭秘
server 层会创建一个 SAVEPOINT 对象,用于存放 savepoint 信息。binlog 会把 binlog offset 写入 server 层为它分配的一块 8 字节的内存里。 InnoDB 会维护自己的 savepoint...【详细内容】
2024-04-03  爱可生开源社区    Tags:MySQL   点击:(5)  评论:(0)  加入收藏
MySQL 核心模块揭秘,你看明白了吗?
为了提升分配 undo 段的效率,事务提交过程中,InnoDB 会缓存一些 undo 段。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存。1. 关于缓存 undo 段为了提升分...【详细内容】
2024-03-27  爱可生开源社区  微信公众号  Tags:MySQL   点击:(10)  评论:(0)  加入收藏
MySQL:BUG导致DDL语句无谓的索引重建
对于5.7.23之前的版本在评估类似DDL操作的时候需要谨慎,可能评估为瞬间操作,但是实际上线的时候跑了很久,这个就容易导致超过维护窗口,甚至更大的故障。一、问题模拟使用5.7.22...【详细内容】
2024-03-26  MySQL学习  微信公众号  Tags:MySQL   点击:(8)  评论:(0)  加入收藏
从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
ByteHouse是一款OLAP引擎,具备查询效率高的特点,在硬件需求上相对较低,且具有良好的水平扩展性,如果数据量进一步增长,可以通过增加服务器数量来提升处理能力。本文将从兴趣圈层...【详细内容】
2024-03-22  字节跳动技术团队    Tags:ByteHouse   点击:(23)  评论:(0)  加入收藏
MySQL自增主键一定是连续的吗?
测试环境:MySQL版本:8.0数据库表:T (主键id,唯一索引c,普通字段d)如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不...【详细内容】
2024-03-10    dbaplus社群  Tags:MySQL   点击:(5)  评论:(0)  加入收藏
准线上事故之MySQL优化器索引选错
1 背景最近组里来了许多新的小伙伴,大家在一起聊聊技术,有小兄弟提到了MySQL的优化器的内部策略,想起了之前在公司出现的一个线上问题,今天借着这个机会,在这里分享下过程和结论...【详细内容】
2024-03-07  转转技术  微信公众号  Tags:MySQL   点击:(26)  评论:(0)  加入收藏
MySQL数据恢复,你会吗?
今天分享一下binlog2sql,它是一款比较常用的数据恢复工具,可以通过它从MySQL binlog解析出你要的SQL,并根据不同选项,可以得到原始SQL、回滚SQL、去除主键的INSERT SQL等。主要...【详细内容】
2024-02-22  数据库干货铺  微信公众号  Tags:MySQL   点击:(41)  评论:(0)  加入收藏
如何在MySQL中实现数据的版本管理和回滚操作?
实现数据的版本管理和回滚操作在MySQL中可以通过以下几种方式实现,包括使用事务、备份恢复、日志和版本控制工具等。下面将详细介绍这些方法。1.使用事务:MySQL支持事务操作,可...【详细内容】
2024-02-20  编程技术汇    Tags:MySQL   点击:(50)  评论:(0)  加入收藏
MySQL数据库如何生成分组排序的序号
经常进行数据分析的小伙伴经常会需要生成序号或进行数据分组排序并生成序号。在MySQL8.0中可以使用窗口函数来实现,可以参考历史文章有了这些函数,统计分析事半功倍进行了解。...【详细内容】
2024-01-30  数据库干货铺  微信公众号  Tags:MySQL   点击:(53)  评论:(0)  加入收藏
mysql索引失效的场景
MySQL中索引失效是指数据库查询时无法有效利用索引,这可能导致查询性能显著下降。以下是一些常见的MySQL索引失效的场景:1.使用非前导列进行查询: 假设有一个复合索引 (A, B)。...【详细内容】
2024-01-15  小王爱编程  今日头条  Tags:mysql索引   点击:(82)  评论:(0)  加入收藏
站内最新
站内热门
站内头条