成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

MySQL:BUG導致DDL語句無謂的索引重建

數據庫 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操作除了翻看官方文檔以外,都需要在相同版本的數據庫測試環境測試其耗時是否達到預估水平。

責任編輯:趙寧寧 來源: MySQL學習
相關推薦

2010-11-16 09:18:39

oracle重建索引

2023-08-14 08:32:42

MySQL數據庫

2020-12-08 09:45:07

MySQL數據庫索引

2010-10-12 16:44:36

MySQL語句

2023-06-12 09:09:19

MySQLDDLNSTANT

2021-09-27 10:15:10

故障業務方電腦

2010-10-08 16:20:35

MySQL語句

2022-07-12 09:36:18

數據庫查詢

2010-11-16 09:49:22

Oracle重建索引

2015-09-02 13:38:38

Windows 10搜索索引

2011-08-09 16:15:23

OracleDDL語句DML語句

2024-06-11 00:04:00

對象AdvisorAdvice

2023-11-29 14:20:16

iOS 17Bug蘋果

2022-06-27 07:23:44

MySQL常量優化

2019-08-20 22:06:32

Oracle數據庫索引

2023-01-04 09:29:03

線程業務代碼

2021-09-11 19:00:54

Intro元素MemoryCache

2009-10-21 16:34:03

Oracle用戶名重建索引

2023-02-26 00:00:06

MySQL索引故障

2024-06-12 12:59:16

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 手机av在线| 免费视频一区二区三区在线观看 | 黄色免费观看网站 | 99久久久无码国产精品 | 国产亚洲人成a在线v网站 | 久久国产香蕉 | 日日摸日日爽 | 国产偷录叫床高潮录音 | av毛片| 久久久久亚洲精品中文字幕 | a级大片免费观看 | 久久久久黑人 | 日韩国产一区二区三区 | 日本精品一区二区三区四区 | 激情 一区 | 精品国产一区二区三区久久 | www.久久.com| 日本亚洲精品 | 中文字幕欧美日韩 | 欧美视频在线播放 | 国产一区二区免费 | 青青草综合| 在线中文字幕第一页 | 亚洲网站在线观看 | 男女精品久久 | 精品国产欧美一区二区三区不卡 | 国产女人与拘做视频免费 | 亚洲视频二区 | 天天干天天玩天天操 | 国产1区在线 | 天天综合日日夜夜 | 日韩a在线| 特黄视频| 国产精品久久久久影院色老大 | 亚洲日日夜夜 | 国产ts一区 | 欧美xxxx色视频在线观看免费 | 日韩2020狼一二三 | 欧美11一13sex性hd | 日韩久久中文字幕 | 日一日操一操 |