[转帖]MySQL 8.0 Instant Add Column功能解析

mysql,instant,add,column,功能,解析 · 浏览次数 : 0

小编点评

**内容简介** 生成内容时需要带排版。 **内容** **1. Instant 添加字段** * `instant` 函数接受一个 `add_column` 参数,该参数包含以下元素: * `table_name`:要添加字段的表名称。 * `column_name`:要添加字段的名称。 * `data_type`:要添加字段的数据类型。 * `null_column`:是否将该字段设置为空值的列名。 **2. 创建存储表结构** * `instant` 函数还接受一个 `store_table_structure` 参数,该参数包含以下元素: * `table_name`:要创建一个存储表结构的表名称。 * `columns`:要定义要创建的表字段。 **3. 设置表结构** * `instant` 函数还可以设置表结构的属性,例如列顺序、默认值等。 **4. 执行存储表结构** * `instant` 函数将执行存储表结构的操作,例如创建表、添加字段等。 **5. 示例** ```python # Instant 添加字段 instant.add_column(table_name, column_name, data_type, null_column) # 创建存储表结构 instant.store_table_structure(table_name, columns) ``` **6. 注意事项** * `instant` 函数只支持 `add_column` 和 `store_table_structure` 方法,其他方法不能使用。 * `instant` 函数的执行结果可能需要重新启动 MySQL 服务。 * `instant` 函数的执行结果可能与存储表结构的变更有关。

正文

https://zhuanlan.zhihu.com/p/408702204

 

概述

DDL(Data Definition Language)是数据库内部的对象进行创建、删除、修改的操作语言,主要包括:加减列、更改列类型、加减索引等类型。数据库的模式(schema)会随着业务的发展不断变化,如果没有高效的DDL功能,每一次变更都有可能影响业务,甚至产生故障。MySQL在8.0以前就已经支持Online DDL,在执行时能够不阻塞其它DML(Insert/Update/Delete)操作,但许多重要的DDL操作,如加列、减列等,仍旧需要等待很长时间(根据数据量的大小)才会生效。为了提高表结构变更的效率,MySQL在8.0.12版本支持了Instant DDL功能,不需要修改存储层数据就可以快速完成DDL。

语法

执行DDL的ALTER语句增加了新的关键字INSTANT,用户可以显式地指定,MySQL也会自动选择合适的算法,因此Instant DDL对用户是透明的。

ALTER TABLE tbl_name
    [alter_specification [, alter_specification] ...]
    [partition_options]

alter_specification:
    table_options
  | ADD [COLUMN] col_name column_definition
        [FIRST | AFTER col_name]
  | ADD [COLUMN] (col_name column_definition,...)
  ....
  | ALGORITHM [=] {DEFAULT|INSTANT|INPLACE|COPY}

备注:
 1.DEFAULT:MySQL自己选择锁定资源最少的方式
 2.INSTANT:只需要更新数据字典中的元数据, 很快完成
 3.INPLACE:此变更由InnoDB引擎独立完成, 不需要使用Redo log等, 可以节省开销
 4.COPY:此变更会重建聚簇索引, 执行DDL的时候会创建临时表

快速DDL支持类型

  • Instant add column
    • 当一条alter语句中同时存在不支持instant的ddl时,则无法使用
    • 只能顺序加列
    • 不支持压缩表、不支持包含全文索引的表
    • 不支持临时表,临时表只能使用copy的方式执行DDL
    • 不支持那些在数据词典表空间中创建的表

 

  • 修改索引类型
  • 修改ENUM/SET类型的定义
    • 存储的大小不变时
    • 向后追加成员

 

  • 增加或删除类型为virtual的generated column
  • RENAME TABLE操作

Instant Add Column

简介

随着业务的发展,加字段是最常见表结构变更类型。Instant add column功能不需要修改存储层数据,更不需要重建表,只改变了存储在系统表中的表结构,其执行效率非常高。解决了以下业务上的痛点:

  • 对大表的加字段操作通常需要耗时十几个小时甚至数天的时间
  • 加字段过程中需要创建临时表,消耗大量存储资源
  • binlog复制是事务维度的,DDL会造成主备延时

在实现上,MySQL并没有在系统表中记录多个版本的schema,而是非常取巧的扩展了存储格式。在已有的info bits区域和新增的字段数量区域记录了instant column信息,instant add column之前的数据不做任何修改,之后的数据按照新格式存储。同时在系统表的private_data字段存储了instant column的默认值信息。查询时,读出的老记录只需要增加instant column默认值,新记录则按照新的存储格式进行解析,做到了新老格式的兼容。当然,这种实现方式带来的限制就是只能顺序加字段。

官方设计文档详见:。本文主要梳理了新的存储格式、DDL、查询以及插入的执行流程。

Online Add Column流程

8.0.12版本之前的MySQL在进行加列操作时,需要更新数据字典并重建表空间,所有的数据行都必须改变长度用于存放增加的数据,DDL操作运行时间很长,占用大量系统资源,更需要额外的磁盘空间(建立临时表),影响系统吞吐,而且一旦执行过程中发生crash,恢复时间也很长。

主要流程:

 

Instant Add Column流程

Instant add column在增加列时,实际上只是修改了schema,并没有修改原来存储在文件中的行记录,不需要执行最耗时的rebuild和apply row log过程,因此效率非常高。

主要流程:

 

新的数据字典信息

在执行instant add column的过程中,MySQL会将第一次intant add column之前的字段个数以及每次加的列的默认值保存在tables系统表的se_private_data字段中。

  • dd::Table::se_private_data::instant_col: 第一次instant ADD COLUMN之前表上面的列的个数, 具体过程详见函数dd_commit_instant_table。
  • dd::Column::se_private_data::default_null: 标识instant column的默认值是否为NULL,具体过程详见函数dd_add_instant_columns。
  • dd::Column::se_private_data::default:当instant column的默认值不是NULL时存储具体的默认值,column default value需要从innodb类型byte转换成se_private_data中的char类型,具体过程详见函数dd_add_instant_columns。

载入数据字典

MySQL从系统表读取表定义时,会将instant column相关的信息载入到InnoDB的表对象dict_table_t和索引对象dict_index_t中。

  • dict_table_t::n_instant_cols: 第一次instant add column之前的非虚拟字段个数(包含系统列), 具体过程详见函数dd_fill_dict_table
  • dict_index_t::instant_cols: 用于标示是否存在Instant column,具体过程详见函数dict_index_add_to_cache_w_vcol
  • dict_index_t::n_instant_nullable:第一次instant add column之前的可为NULL的字段个数,具体过程详见函数dict_index_add_to_cache_w_vcol
  • dict_col_t::instant_default: 存储默认值及其长度,具体过程详见函数dd_fill_instant_columns

记录格式

InnoDB存储引擎支持的行格式包括REDUNDANT,COMPACT以及DYNAMIC,REDUNDANT类型的行记录了完整的元数据信息,可以自解析,但对于COMPACT和DYNAMIC类型,为了减少存储空间,其行内并不包括元数据,尤其是列的个数,因此解析记录时需要额外的元数据辅助。

以COMPACT为例,其行格式为:

 

变长字段长度列表

COMPACT行格式的首部是一个变长字段长度列表,这个列表是按照字段的顺序逆序放置的。如果字段的字义长度大于255个字节,或者字段的数据类型为BLOB的,则用2个字节来存储该字段的长度;如果定义长度小于128个字节,或者小于256个字节,但类型不是BLOB类型的,则用一个字节来存储该字段的长度,除此之外都用2个字节来存储。

NULL字段标志位

变长字段长度列表之后是NULL字段标志位,这个标志位用于记录中哪些字段的值是null,只存储nullable属性的字段,不会存储属性为not nulll的字段。每一bit都表示一个nullable的字段的null属性,如果为null则设置为1,这个bit vector也是按照字段的顺序逆序放置的,整个标志位长度取决于记录中nullable字段的个数,而是以8为单位,满8个null字段就多1个字节,不满8个也占用1个字节,高位用0补齐。

记录头信息

记录头信息最开始的4个bit组成了info bits, 目前只使用了两个bit,具体含义如下:

名称大小(bit)描述

新的记录格式

为了支持instant add column, 针对COMPACT和DYNAMIC类型,引入了新的记录格式,主要为了记录字段的个数信息。

  • 如果没有执行过instant add column操作,则表的行记录格式保持不变。
  • 如果执行过instant add column操作,则所有新的记录都会设置一个特殊的标记,同时在记录内存储字段的个数。

 

 

这个特殊的INSTANT_FLAG使用了info bits中的一个bit位,如果记录是第一次instant add column之后插入的,该flag被设置为1,且记录中会使用1或2个字节来存储字段的个数,如果字段个数小于等于127,则使用1个字节存储,否则使用2个字节存储。 相关代码:

// 返回用于存储字段数量的字节数
uint8_t rec_get_n_fields_length(ulint n_fields) {
  return (n_fields > REC_N_FIELDS_ONE_BYTE_MAX ? 2 : 1);
}

// 设置字段数量
uint8_t rec_set_n_fields(rec_t *rec, ulint n_fields) {
  // 指向记录头信息的前一个字节
  byte *ptr = rec - (REC_N_NEW_EXTRA_BYTES + 1);

  ut_ad(n_fields < REC_MAX_N_FIELDS);
  
  // 如果字段数量小于或等于127
  if (n_fields <= REC_N_FIELDS_ONE_BYTE_MAX) {
    // 在当前位置存储字段数量
    *ptr = static_cast<byte>(n_fields);
    // 存储字段数量的字节数是1
    return (1);
  }
  
  // 如果字段数量大于127,向前移动一个字节
  --ptr;
  // 第一个字节记录低8位数据
  *ptr++ = static_cast<byte>(n_fields & 0xFF);
  // 第二个字节记录高8位数据
  *ptr = static_cast<byte>(n_fields >> 8);
  ut_ad((*ptr & 0x80) == 0);
  *ptr |= REC_N_FIELDS_TWO_BYTES_FLAG;
  
  // 存储字段数量的字节数是2
  return (2);
}

表结构和初始化数据

> create table t1(id int, c1 varchar(10), c2 varchar(10), c3 char(10), c4 varchar(10), primary key(id)) row_format=compact;
Query OK, 0 rows affected (0.24 sec)
    
> insert into t1 values(1, 'a','ab','ab','ccc');
Query OK, 1 row affected (0.01 sec)
    
> insert into t1 values(2, 'b', NULL, NULL, 'ddd');
Query OK, 1 row affected (0.01 sec)
    
> select * from t1;
+----+------+------+------+------+
| id | c1   | c2   | c3   | c4   |
+----+------+------+------+------+
|  1 | a    | ab   | ab   | ccc  |
|  2 | b    | NULL | NULL | ddd  |
+----+------+------+------+------+
2 rows in set (0.00 sec)

idb文件解析

$ hexdump -C -v t1.ibd > t1.txt

00010070  73 75 70 72 65 6d 75 6d  03 0a 02 01 00 00 00 10  |supremum........|
00010080  00 29 80 00 00 01 00 00  00 00 07 d8 9e 00 00 00  |.)..............|
00010090  94 01 10 61 61 62 61 62  20 20 20 20 20 20 20 20  |...aabab        |
000100a0  63 63 63 03 01 06 00 00  18 00 1f 80 00 00 02 00  |ccc.............|
000100b0  00 00 00 07 d9 9f 00 00  00 94 01 10 62 64 64 64  |............bddd|
  • 第一行记录从0x00010078开始
起始地址数据长度(字节)解析
  • 第二行记录从0x000100a3开始
起始地址数据长度(字节)解析

执行instant add column

> alter table t1 add column (c5 varchar(10)), ALGORITHM = INSTANT;
Query OK, 0 rows affected (0.28 sec)
    
> insert into t1 values (3, 'c', NULL, NULL, 'eee', 'eeee');
Query OK, 1 row affected (0.06 sec)
    
> select * from t1;
+----+------+------+------+------+------+
| id | c1   | c2   | c3   | c4   | c5   |
+----+------+------+------+------+------+
|  1 | a    | ab   | ab   | ccc  | NULL |
|  2 | b    | NULL | NULL | ddd  | NULL |
|  3 | c    | NULL | NULL | eee  | eeee |
+----+------+------+------+------+------+
3 rows in set (0.00 sec)

idb文件解析

$ hexdump -C -v t1.ibd > t1.txt

00010070  73 75 70 72 65 6d 75 6d  03 0a 02 01 00 00 00 10  |supremum........|
00010080  00 29 80 00 00 01 00 00  00 00 07 d8 9e 00 00 00  |.)..............|
00010090  94 01 10 61 61 62 61 62  20 20 20 20 20 20 20 20  |...aabab        |
000100a0  63 63 63 03 01 06 00 00  18 00 1f 80 00 00 02 00  |ccc.............|
000100b0  00 00 00 07 d9 9f 00 00  00 94 01 10 62 64 64 64  |............bddd|
000100c0  04 03 01 06 08 80 00 20  ff a6 80 00 00 03 00 00  |....... ........|
000100d0  00 00 07 e7 a0 00 00 00  95 01 10 63 65 65 65 65  |...........ceeee|
000100e0  65 65 65 00 00 00 00 00  00 00 00 00 00 00 00 00  |eee.............|
  • 前两行记录没有变化
  • 第三行记录从0x000100c0开始
起始地址数据长度(字节)解析

查询

查询的流程没有变化,关键点在于如何准确地解析记录,对于没有存储在记录中的instant column, 直接填默认值即可,关键函数是rec_init_null_and_len_comp。 主要流程:

|-mysql_execute_command
    |-Sql_cmd_dml::execute
      |-Sql_cmd_dml::execute_inner
        |-JOIN::exec
          |-do_select
            |-sub_select
              |-TableScanIterator::Read
                |-handler::ha_rnd_next
                  |-ha_innobase::rnd_next
                    |-ha_innobase::index_first
                      |-ha_innobase::index_read
                        |-row_search_mvcc
                          |-rec_get_offsets_func
                            |-rec_init_offsets
                              |-rec_init_offsets_comp_ordinary
                                |-rec_init_null_and_len_comp
                                  |-*nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1); // REC_N_NEW_EXTRA_BYTES = 5, 
                                  |-if (!index->has_instant_cols())
                                    |-*n_null = index->n_nullable;
                                  |-else if (rec_get_instant_flag_new(rec) /* Row inserted after first instant ADD COLUMN */
                                    |-non_default_fields = rec_get_n_fields_instant
                                    |-*nulls -= length;
                                    |-*n_null = index->get_n_nullable_before(non_default_fields);
                                  |-else /* Row inserted before first instant ADD COLUMN */
                                    |-*n_null = index->n_instant_nullable;
                                    |-non_default_fields = index->get_instant_fields();
                          |-row_sel_store_mysql_rec
                            |-for (i = 0; i < prebuilt->n_template; i++) 
                              |-row_sel_store_mysql_field // row_sel_store_mysql_field_func
                                |-rec_get_nth_field_instant // 如果是记录中的,则从记录中读取,否则返回其默认值
                                |-row_sel_field_store_in_mysql_format_func

插入

执行instant add column后,老数据的格式没有变化,新插入的数据按照新格式存储,关键函数是rec_convert_dtuple_to_rec_comp,该函数将MySQL逻辑记录转换为COMPACT格式的物理记录。此外,函数rec_set_instant_flag_new在记录的Info bits字段设置REC_INFO_INSTANT_FLAG,表示这个记录是instant add column之后创建的。

bool rec_convert_dtuple_to_rec_comp(rec_t *rec, const dict_index_t *index,
                                    const dfield_t *fields, ulint n_fields,
                                    const dtuple_t *v_entry, ulint status,
                                    bool temp) {
  const dfield_t *field;
  const dtype_t *type;
  byte *end;
  byte *nulls;
  byte *lens = NULL;
  ulint len;
  ulint i;
  ulint n_node_ptr_field;
  ulint fixed_len;
  ulint null_mask = 1;
  ulint n_null = 0;
  ulint num_v = v_entry ? dtuple_get_n_v_fields(v_entry) : 0;
  bool instant = false;

  ut_ad(temp || dict_table_is_comp(index->table));

  if (n_fields != 0) {
    // 获得nullable字段个数
    n_null = index->has_instant_cols()
                 ? index->get_n_nullable_before(static_cast<uint32_t>(n_fields))
                 : index->n_nullable;
  }

  if (temp) {
    ut_ad(status == REC_STATUS_ORDINARY);
    ut_ad(n_fields <= dict_index_get_n_fields(index));
    n_node_ptr_field = ULINT_UNDEFINED;
    nulls = rec - 1;
    if (dict_table_is_comp(index->table)) {
      /* No need to do adjust fixed_len=0. We only
      need to adjust it for ROW_FORMAT=REDUNDANT. */
      temp = false;
    }
  } else {
    ut_ad(v_entry == NULL);
    ut_ad(num_v == 0);
    // 指向指向记录头信息的前一个字节
    nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);

    switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
      case REC_STATUS_ORDINARY:
        ut_ad(n_fields <= dict_index_get_n_fields(index));
        n_node_ptr_field = ULINT_UNDEFINED;
        
        // 如果存在instant column,那么还存在字段个数信息,调用rec_set_n_fields设置
        // 字段数量,并返回存储字节数, 如果字段数量不大于127,存储长度为1字节,否则为2字节
        if (index->has_instant_cols()) {
          uint32_t n_fields_len;
          n_fields_len = rec_set_n_fields(rec, n_fields);
          // nulls指向存储字段数量信息的前一个字节,也就是null标志位最后一个字节开始的位置
          nulls -= n_fields_len;
          instant = true;
        }
        break;
      case REC_STATUS_NODE_PTR:
        ut_ad(n_fields ==
              static_cast<ulint>(
                  dict_index_get_n_unique_in_tree_nonleaf(index) + 1));
        n_node_ptr_field = n_fields - 1;
        n_null = index->n_instant_nullable;
        break;
      case REC_STATUS_INFIMUM:
      case REC_STATUS_SUPREMUM:
        ut_ad(n_fields == 1);
        n_node_ptr_field = ULINT_UNDEFINED;
        break;
      default:
        ut_error;
        return (instant);
    }
  }

  end = rec;

  if (n_fields != 0) {
    // 指向变长字段长度列表最后一个字节开始的位置
    lens = nulls - UT_BITS_IN_BYTES(n_null);
    /* clear the SQL-null flags */
    memset(lens + 1, 0, nulls - lens);
  }

  /* Store the data and the offsets */
  
  // 遍历所有字段
  for (i = 0; i < n_fields; i++) {
    const dict_field_t *ifield;
    dict_col_t *col = NULL;

    field = &fields[i];

    type = dfield_get_type(field);
    len = dfield_get_len(field);

    if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
      ut_ad(dtype_get_prtype(type) & DATA_NOT_NULL);
      ut_ad(len == REC_NODE_PTR_SIZE);
      memcpy(end, dfield_get_data(field), len);
      end += REC_NODE_PTR_SIZE;
      break;
    }
    
    // 如果不是not null类型的字段
    if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
      /* nullable field */
      ut_ad(n_null--);
      
      // 如果写满8个,则offset向左移1位,并将null_mask置为1
      if (UNIV_UNLIKELY(!(byte)null_mask)) {
        nulls--;
        null_mask = 1;
      }

      ut_ad(*nulls < null_mask);

      // 如果字段是null
      if (dfield_is_null(field)) {
        // 将null标志位设为1
        *nulls |= null_mask;
        // 向前移1位
        null_mask <<= 1;
        continue;
      }

      null_mask <<= 1;
    }
    /* only nullable fields can be null */
    ut_ad(!dfield_is_null(field));

    ifield = index->get_field(i);
    fixed_len = ifield->fixed_len;
    col = ifield->col;
    if (temp && fixed_len && !col->get_fixed_size(temp)) {
      fixed_len = 0;
    }

    /* If the maximum length of a variable-length field
    is up to 255 bytes, the actual length is always stored
    in one byte. If the maximum length is more than 255
    bytes, the actual length is stored in one byte for
    0..127.  The length will be encoded in two bytes when
    it is 128 or more, or when the field is stored externally. */
    if (fixed_len) {
#ifdef UNIV_DEBUG
      ulint mbminlen = DATA_MBMINLEN(col->mbminmaxlen);
      ulint mbmaxlen = DATA_MBMAXLEN(col->mbminmaxlen);

      ut_ad(len <= fixed_len);
      ut_ad(!mbmaxlen || len >= mbminlen * (fixed_len / mbmaxlen));
      ut_ad(!dfield_is_ext(field));
#endif /* UNIV_DEBUG */
    } else if (dfield_is_ext(field)) {
      ut_ad(DATA_BIG_COL(col));
      ut_ad(len <= REC_ANTELOPE_MAX_INDEX_COL_LEN + BTR_EXTERN_FIELD_REF_SIZE);
      *lens-- = (byte)(len >> 8) | 0xc0;
      *lens-- = (byte)len;
    } else {
      /* DATA_POINT would have a fixed_len */
      ut_ad(dtype_get_mtype(type) != DATA_POINT);
#ifndef UNIV_HOTBACKUP
      ut_ad(len <= dtype_get_len(type) ||
            DATA_LARGE_MTYPE(dtype_get_mtype(type)) ||
            !strcmp(index->name, FTS_INDEX_TABLE_IND_NAME));
#endif /* !UNIV_HOTBACKUP */
      if (len < 128 ||
          !DATA_BIG_LEN_MTYPE(dtype_get_len(type), dtype_get_mtype(type))) {
        *lens-- = (byte)len;
      } else {
        ut_ad(len < 16384);
        // 设置变长字段长度信息
        *lens-- = (byte)(len >> 8) | 0x80;
        *lens-- = (byte)len;
      }
    }
    if (len > 0) memcpy(end, dfield_get_data(field), len);
    end += len;
  }

  if (!num_v) {
    return (instant);
  }

  /* reserve 2 bytes for writing length */
  byte *ptr = end;
  ptr += 2;

  ......
  mach_write_to_2(end, ptr - end);

  return (instant);
}

总结

MySQL的instant add column功能极大地提高了增加字段的效率,执行过程中不需要修改存储中的数据,只改变了存储在系统表中的表结构。期待MySQL能支持更多更实用的instant DDL类型,例如任意顺序加字段、删字段、修改字段类型等,这可能需要引入更复杂的多版本schema技术,设置将更多的schema信息下沉到存储层,实现难度无疑会大大增加。

与[转帖]MySQL 8.0 Instant Add Column功能解析相似的内容:

[转帖]MySQL 8.0 Instant Add Column功能解析

https://zhuanlan.zhihu.com/p/408702204 概述 DDL(Data Definition Language)是数据库内部的对象进行创建、删除、修改的操作语言,主要包括:加减列、更改列类型、加减索引等类型。数据库的模式(schema)会随着业务的发展不断变化,如果没有

[转帖]MySQL 8.0.19 instant add column,亿级数据秒速增加字段

一、MySQL DDL 的方法 MySQL 在大型表上的 DDL 会带来耗时较久、负载较高、额外空间占用、MDL、主从同步延时等情况。需要特别引起重视,而MySQL 的 DDL 有很多种方法。 MySQL 本身自带三种方法,分别是:copy、inplace、instant。 copy 算法为最古老的

[转帖]MySQL 8.0: When to use utf8mb3 over utf8mb4?

https://dev.mysql.com/blog-archive/mysql-8-0-when-to-use-utf8mb3-over-utf8mb4/ MySQL 8.0: When to use utf8mb3 over utf8mb4? Posted on May 19, 2017 by 

[转帖]MySQL 8.0新特性和性能数据

https://plantegg.github.io/2022/07/03/MySQL8.0%E7%9A%84%E4%B8%80%E4%BA%9B%E6%95%B0%E6%8D%AE/ MySQL 8.0带来了很多新特性 针对性能方面介绍全在这个PPT( http://dimitrik.free.f

【转帖】MySQL 8.0.32如期而至

MySQL 8.0版本计划 MySQL 8.0开始采用快速迭代开发模式,基本上是每隔3个月就发布一个新的小版本。去年1月18日(2022.1.18)发布MySQL 8.0.28,今年1月17日发布MySQL 8.0.32,再看看其他几个版本的时间,还真是贼守时啊。 版本发布时间上一年版本上一年发布时

【转帖】MySQL 8.0 hash join有重大缺陷?

我并不这么看。 友情提醒:本文建议在PC端阅读。 徐春阳老师发文爆MySQL 8.0 hash join有重大缺陷。 文章核心观点如下:多表(比如3个个表)join时,只会简单的把表数据量小的放在前面作为驱动表,大表放在最后面,从而导致可能产生极大结果集的笛卡尔积,甚至耗尽CPU和磁盘空间。 就此现

[转帖]【MySQL】MySQL 8.0 redo log写入性能问题分析

http://kernelmaker.github.io/MySQL_8_core 最近对比了MySQL 5.6和8.0在8核环境下oltp_write_only的性能,发现8.0写入性能(QPS 6-7万)反而低于5.6版本的(QPS 14万),所以进一步测试分析了下redo log这里可能导致性

[转帖]MySQL Performance : 8.0 and UTF8 impact

http://dimitrik.free.fr/blog/posts/mysql-performance-80-and-utf8-impact.html 2018-04-26 00:58 | MySQL, Performance, UTF8 by Dimitri The world is movin

[转帖]第一章 MySQL 8.0 介绍及安装配置

第一章 MySQL 8.0 介绍及安装配置 https://www.jianshu.com/p/d190c6b3520d 本课程,适合具备一定Linux运维或者开发基础的朋友,课程定级中、高级DBA。只要掌握80%,轻松助力薪资15k-25K。课程内容均来自与MySQL官网+MySQL源码。配套精品

[转帖]【MySQL 8】MySQL 5.7都即将停只维护了,是时候学习一波MySQL 8了

https://www.cnblogs.com/paul8339/p/17026571.html 阅读目录 账户与安全 索引增强 原子DDL操作 通用表达式(CTE) 其他 MySQL 8新特性选择MySQL 8的背景:MySQL 5.6已经停止版本更新了,对于 MySQL 5.7 版本,其将于 2