自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL:BUG導(dǎo)致DDL語句無謂的索引重建

數(shù)據(jù)庫 MySQL
對于5.7.23之前的版本在評估類似DDL操作的時候需要謹(jǐn)慎,可能評估為瞬間操作,但是實際上線的時候跑了很久,這個就容易導(dǎo)致超過維護窗口,甚至更大的故障。

一、問題模擬

使用5.7.22版本:

建表語句,注意這里字段a包含了一個索引,這是觸發(fā)這個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

數(shù)據(jù)量:
mysql> select count(*) from testmy;
+----------+
| count(*) |
+----------+
|   262144 |
+----------+
1 row in set (5.17 sec)

執(zhí)行DDL語句:
alter table testmy modify `a` varchar(30) comment 'test1111';

本DDL語句主要完成:

  • 擴展varchar從24*4到30*4
  • 更改字段的comment

按照常理來講這個DDL是只修改元數(shù)據(jù)的,因此應(yīng)該瞬間完成,但是實際在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的長度,只要字符集字節(jié)數(shù)量*字符數(shù)量不跨越256,那么就是修改元數(shù)據(jù),不會重建索引。

三、問題分析

既然不符合官方文檔的說明,那么這個問題肯定是某種BUG導(dǎo)致。當(dāng)我們進行DDL操作的時候,需要對比更改部分和現(xiàn)有的數(shù)據(jù)字典中標(biāo)定義的差別,然后根據(jù)這些差別來定義操作方式,然后根據(jù)操作方式來判斷哪一種DDL 方式比較合適,關(guān)于定義操作方式的部分來自于函數(shù)fill_alter_inplace_info,而在函數(shù)中會根據(jù)新表的索引和老表的索引字段的長度判斷是否需要drop索引和新建索引,代碼中體現(xiàn)為如下:

  /*
    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++) //循環(huán)老表的索引
  {
    /* 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,因此就需要進行索引的刪除和重建,因此關(guān)鍵就是函數(shù)has_index_def_changed的更改,我們先看5.7.22的這個BUG相關(guān)的判斷點:

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

也就是當(dāng)索引字段長度更改了就返回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)這個條件是否滿足,而判定的函數(shù)為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字節(jié)

那么則返回IS_EQUAL_PACK_LENGTH,因此就這個點上has_index_def_changed函數(shù)就會返回false,不會刪除和重建索引了。

四、相關(guān)BUG

這個BUG雖然有點老了,是5.7.23修復(fù)的,如下:

但是對于5.7.23之前的版本在評估類似DDL操作的時候需要謹(jǐn)慎,可能評估為瞬間操作,但是實際上線的時候跑了很久,這個就容易導(dǎo)致超過維護窗口,甚至更大的故障,因此還是建議任何DDL操作除了翻看官方文檔以外,都需要在相同版本的數(shù)據(jù)庫測試環(huán)境測試其耗時是否達到預(yù)估水平。

責(zé)任編輯:趙寧寧 來源: MySQL學(xué)習(xí)
相關(guān)推薦

2023-08-14 08:32:42

MySQL數(shù)據(jù)庫

2010-11-16 09:18:39

oracle重建索引

2020-12-08 09:45:07

MySQL數(shù)據(jù)庫索引

2010-10-12 16:44:36

MySQL語句

2010-10-08 16:20:35

MySQL語句

2023-06-12 09:09:19

MySQLDDLNSTANT

2021-09-27 10:15:10

故障業(yè)務(wù)方電腦

2022-07-12 09:36:18

數(shù)據(jù)庫查詢

2011-08-09 16:15:23

OracleDDL語句DML語句

2010-11-16 09:49:22

Oracle重建索引

2015-09-02 13:38:38

Windows 10搜索索引

2022-06-27 07:23:44

MySQL常量優(yōu)化

2024-06-11 00:04:00

對象AdvisorAdvice

2023-11-29 14:20:16

iOS 17Bug蘋果

2019-08-20 22:06:32

Oracle數(shù)據(jù)庫索引

2009-10-21 16:34:03

Oracle用戶名重建索引

2024-06-12 12:59:16

2023-01-04 09:29:03

線程業(yè)務(wù)代碼

2021-09-11 19:00:54

Intro元素MemoryCache

2019-08-27 20:30:38

MySQLOnline DDL數(shù)據(jù)庫
點贊
收藏

51CTO技術(shù)棧公眾號