在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

MySQL 8.0 29 instant add/drop column性能回退問題

數據庫和存儲 ? 來源:MySQL內核剖析 ? 2023-12-11 11:20 ? 次閱讀

影響范圍: 從 8.0.29 版本開始, 在read heavy 場景, 性能可能有 5%~10% 的性能回退

MySQL 官方在8.0.29 里面加了instant add/drop column 能力, 能夠實現 instant add 或者 drop cloumn 到表的任意位置. PolarDB 在這基礎上增加了可以 Instant 修改列的能力, 具體可以看我們的月報

instant DDL 核心觀點只有一個: don’t touch any row but update the metadata only, 也就是僅僅去修改 Data Dictionary(DD) 信息, 而不去修改數據信息,這樣才有可能做到 Instant.

具體的做法就是給每一個行增加了row_version, 然后DD 本身就是多版本, 不同的數據信息用不同的DD 信息去解析.

首先一個record 是否有row_version 信息添加到了Record info bits 里面.

info bits 包含有deleted flag, min record 等等信息, 后來在8.0.13 的時候增加record 是否有Instant ADD column 信息. 在 8.0.29 版本中增加了record 是否有 row_version 信息.

8976f392-97c9-11ee-8b88-92fbcf53809c.png

以上是這個 issue 背景, Instant add/drop column 的原理, 但是原因在哪里呢?

從Markus 提交上來的Flamegraph 可以看到, 在 8.0.33 里面 rec_get_offsets/cmp_dtuple_rec/rec_get_nth_field 等等相比 8.0.28 占比明顯增多了. 整個 row_serch_mvcc 的調用開銷也增加了.

899071f0-97c9-11ee-8b88-92fbcf53809c.png

899abade-97c9-11ee-8b88-92fbcf53809c.png

核心原因由于數據record 增加了 row_version 信息, 導致在執行數據解析的函數 rec_get_offsets/rec_get_nth_field 等函數中增加了很多額外的判斷, 并且官方把很多 inline function 改成了 non-inline.

為了驗證想法, 我們做了 3 個地方的修改, 具體可以看 Issue 上面的代碼提交:

1. 將一些 non-inline function 改回inline function

從 inline => non-inline. 修改的函數如下:

8.0.27

rec_get_nth_field => inline

rec_get_nth_field_offs => inline

rec_init_offsets_comp_ordinary => inline

rec_offs_nth_extern => inline

8.2.0

rec_get_nth_field => non-inline

rec_get_nth_field_offs => non-inline

rec_init_offsets_comp_ordinary => non-inline

rec_offs_nth_extern => non-inline

我們測試下來在 oltp_read_only 場景里面, 將這些 non-inline 函數改成 inline 以后, 性能可以有 3~5% 左右的提升空間. 具體改動代碼可以在 issue 里面獲得.

2. 簡化get_rec_insert_state 邏輯

8.0.29 增加了 get_rec_insert_state 函數, 需要判斷當前 record 是來自哪一個版本升級上來的, 從而使用合適的 DD 代碼邏輯進行解析. 如果是包含有 row_version 版本, 還需要判斷是否帶有 version 信息, 如果沒有 version 信息, 是不是8.0.12 instant add column 版本等等, 這里的邏輯非?,嵥?

所以 REC_INSERT_STATE 的狀態非常多.

enum REC_INSERT_STATE {  /* Record was inserted before first instant add done in the earlier
  implementation. */
  INSERTED_BEFORE_INSTANT_ADD_OLD_IMPLEMENTATION,  /* Record was inserted after first instant add done in the earlier
  implementation. */
  INSERTED_AFTER_INSTANT_ADD_OLD_IMPLEMENTATION,  /* Record was inserted after upgrade but before first instant add done in the
  new implementation. */
  INSERTED_AFTER_UPGRADE_BEFORE_INSTANT_ADD_NEW_IMPLEMENTATION,  /* Record was inserted before first instant add/drop done in the new
  implementation. */
  INSERTED_BEFORE_INSTANT_ADD_NEW_IMPLEMENTATION,  /* Record was inserted after first instant add/drop done in the new
  implementation. */
  INSERTED_AFTER_INSTANT_ADD_NEW_IMPLEMENTATION,  /* Record belongs to table with no verison no instant */
  // 如果index 上面沒有做過instant add 或者 最新的row_version 版本Instant add/drop
  INSERTED_INTO_TABLE_WITH_NO_INSTANT_NO_VERSION,
  NONE
};

具體獲得 insert_state 代碼:

static inline enum REC_INSERT_STATE get_rec_insert_state(    const dict_index_t *index, const rec_t *rec, bool temp) {
  ut_ad(dict_table_is_comp(index->table) || temp);  if (!index->has_instant_cols_or_row_versions()) {    return INSERTED_INTO_TABLE_WITH_NO_INSTANT_NO_VERSION;
  }  /* Position just before info-bits where version will be there if any */
  const byte *v_ptr =
      (byte *)rec -
      ((temp ? REC_N_TMP_EXTRA_BYTES : REC_N_NEW_EXTRA_BYTES) + 1);  const bool is_versioned =
      (temp) ? rec_new_temp_is_versioned(rec) : rec_new_is_versioned(rec);  // 如果有versioned 以后, 這里可以看到version 值是保存在Info bits 和 null field bitmap 中間的1 byte, 如下圖
  const uint8_t version = (is_versioned) ? (uint8_t)(*v_ptr) : UINT8_UNDEFINED;  const bool is_instant = (temp) ? rec_get_instant_flag_new_temp(rec)
                                 : rec_get_instant_flag_new(rec);  // 說明一個Record 不能同時被instalt add 和 row_version 版本instant add/drop 處理過
  // 應該以后默認的新版本是row_version 版本 instant add/drop, 老的要被淘汰
  if (is_versioned && is_instant) {
    ib::error() << "Record has both instant and version bit set in Table '"
                << index->table_name << "', Index '" << index->name()
                << "'. This indicates that the table may be corrupt. Please "
                   "run CHECK TABLE before proceeding.";
  }  enum REC_INSERT_STATE rec_insert_state = REC_INSERT_STATE::NONE;  if (is_versioned) {
    ut_a(is_valid_row_version(version));    if (version == 0) {
      ut_ad(index->has_instant_cols());      // is_versioned 說明record 有row_version, 如果version = 0, 說明是row_version DD 之前插入, 然后row_version DD 做過以后, 又升級了實例, 所以給這些row_version 設置成0
      rec_insert_state =
          INSERTED_AFTER_UPGRADE_BEFORE_INSTANT_ADD_NEW_IMPLEMENTATION;
    } else {      // 最正常的record, row_version DD 之后插入的, 有自己的row_version 版本
      ut_ad(index->has_row_versions());
      rec_insert_state = INSERTED_AFTER_INSTANT_ADD_NEW_IMPLEMENTATION;
    }
  } else if (is_instant) {    // 到這里說明record 上面沒有row_version DD 標記, 只有instant add 標記
    // 說明這個Record 是Instant add 之后插入的record, 并且沒有做過row_version DD
    ut_ad(index->table->has_instant_cols());
    rec_insert_state = INSERTED_AFTER_INSTANT_ADD_OLD_IMPLEMENTATION;
  } else if (index->table->has_instant_cols()) {    // 到這里說明record 上面 沒有row_version DD 和 instant add 標記, 但是這個index 上面有instant add 標記
    // 說明這個record 是instant add 之前就插入的
    rec_insert_state = INSERTED_BEFORE_INSTANT_ADD_OLD_IMPLEMENTATION;
  } else {    // record 上面沒有row_version DD, 也沒用instant add 標記, 并且index 上面也沒用instant add
    // 那么這個Record 是在row_version DD 以及 instant add 做過之前就插入的
    rec_insert_state = INSERTED_BEFORE_INSTANT_ADD_NEW_IMPLEMENTATION;
  }

  ut_ad(rec_insert_state != REC_INSERT_STATE::NONE);  return rec_insert_state;
}

這里雖然 inline enum REC_INSERT_STATE get_rec_insert_state 定義的是 inline, 但是其實這個只是代碼給編譯器的定義, 具體函數是否 Inline 其實是編譯器自己決定的, 最后其實具體運行的時候該函數并沒有 inline, 因為可以從Flamegraph 看到, 說明這個函數是有符號表的信息的, 因此肯定不是 inline 的

89bacf18-97c9-11ee-8b88-92fbcf53809c.png

3. 將 swatch case 改成 if/else, 并且給編譯器提示likely 執行的 branch

最后我們發現 switch case 對于有些明顯的分支預測并不友好, 通過 if/else 可以手動調整哪些 branch 更有可能執行, 從而優化編譯器的選擇.

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 編譯器
    +關注

    關注

    1

    文章

    1634

    瀏覽量

    49146
  • MySQL
    +關注

    關注

    1

    文章

    814

    瀏覽量

    26603

原文標題:#issue 111538 MySQL 8.0 instant add/drop column 性能回退問題

文章出處:【微信號:inf_storage,微信公眾號:數據庫和存儲】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    MySQL8.0 新特性:Partial Update of LOB Column

    是標記刪除舊記錄,并插入新記錄,顯然這會帶來一些存儲上的開銷(盡管Purge線程會去后臺清理),而寫入的redo log和Binlog的量也會偏高,對于超大列,可能會嚴重影響到性能MySQL8.0
    發表于 06-11 20:23

    ADD8504/ADD8505/ADD8506,pdf da

    The ADD8504, ADD8505, and ADD8506 are 4-, 5-, and 6-channel LCD gamma reference buffers designed
    發表于 09-02 16:16 ?15次下載

    即時效能與閃存微控制器-Instant Performanc

    flash and SRAM. These UHSFMs drop into existing 8051 applications and deliver an instant boost in speed. This application note discusse
    發表于 04-23 13:57 ?548次閱讀

    什么是ADM (Add/Drop Multiplexer)

    什么是ADM (Add/Drop Multiplexer)  英文縮寫: ADM (Add/Drop Multiplexer) 中文譯名: 分插復用器 分  類:
    發表于 02-22 10:10 ?2653次閱讀

    MySql5.6性能優化最佳實踐

    MySql5.6性能優化最佳實踐
    發表于 09-08 08:47 ?13次下載
    <b class='flag-5'>MySql</b>5.6<b class='flag-5'>性能</b>優化最佳實踐

    Instant Raspberry Pi Gaming

    Instant Raspberry Pi Gaming
    發表于 10-24 09:26 ?6次下載
    <b class='flag-5'>Instant</b> Raspberry Pi Gaming

    騰訊云打造MySQL 8.0全新引擎,進一步加速客戶產業升級

    據介紹,騰訊云數據庫 MySQL 8.0的內核可以百分百完全兼容主流MySQL分支。相比官方版本,無論是單機模式、異步模式還是同步模式下, MySQL
    的頭像 發表于 07-09 14:54 ?2363次閱讀

    MySQL 5.7與MySQL 8.0 性能對比

    背景 測試mysql5.7和mysql8.0分別在讀寫,選定,只寫模式下不同并發時的性能(tps,qps) 最早 測試使用版本為mysql5.7.22和
    的頭像 發表于 11-03 09:26 ?1.7w次閱讀
    <b class='flag-5'>MySQL</b> 5.7與<b class='flag-5'>MySQL</b> <b class='flag-5'>8.0</b> <b class='flag-5'>性能</b>對比

    MySql環境一鍵安裝應用程序免費下載

    本文檔的主要內容詳細介紹的是MySql環境一鍵安裝應用程序免費下載。創建Mysql所需環境支持8.0以上版本,暫無測試過8.0以下版本
    發表于 02-26 15:01 ?7次下載

    關于MySQL8.0版本選型的小技巧

    MySQL 8.0 第一個GA(General Availability)版本(正式、可用于生產的版本)于2018/4/19發布至今已有3年。8.0是一個全新的版本,增加了數百項功能新特性,重構了
    的頭像 發表于 03-29 13:45 ?1145次閱讀
    關于<b class='flag-5'>MySQL8.0</b>版本選型的小技巧

    請問mysql8.0不能在grant時創建用戶是什么原因?

    用習慣了MySQL5.7,當在MySQL8.0里創建用戶時,習慣性直接敲GRANT指令,結果報錯了
    的頭像 發表于 08-11 10:16 ?2255次閱讀

    mysql8.0默認字符集是什么

    MySQL 8.0 默認字符集是 utf8mb4。 MySQL 8.0 是當前最新的開源關系型數據庫管理系統,由Oracle公司開發和維護。MySQ
    的頭像 發表于 11-16 14:48 ?1832次閱讀

    mysql數據庫的增刪改查sql語句

    MySQL是一種常用的關系型數據庫管理系統,是許多網站和應用程序的首選數據庫。在MySQL中,我們可以使用SQL(結構化查詢語言)進行數據的增刪改查操作。本文將詳細介紹MySQL數據庫的增刪改查
    的頭像 發表于 11-16 15:41 ?1256次閱讀

    MySQL5.7數據導入8.0版本,這3款工具值得收藏!

    MySQL 5.7數據庫遷移到MySQL 8.0可以使用NineData、MySQL Shell、Percona XtraBackup和Liquibase等工具。每個工具都有自己的優
    的頭像 發表于 11-29 16:47 ?2780次閱讀
    <b class='flag-5'>MySQL</b>5.7數據導入<b class='flag-5'>8.0</b>版本,這3款工具值得收藏!

    GitHub底層數據庫無縫升級到MySQL 8.0的經驗

    GitHub 團隊近日分享了他們將 GitHub.com 的底層數據庫無縫升級到 MySQL 8.0 的經驗。 據介紹,GitHub 使用 MySQL 來存儲大量關系數據,因此在不影響網站服務級別
    的頭像 發表于 12-13 10:21 ?518次閱讀
    GitHub底層數據庫無縫升級到<b class='flag-5'>MySQL</b> <b class='flag-5'>8.0</b>的經驗
    主站蜘蛛池模板: 免费一级毛片在线播放| 成人5252色| 亚洲黄色一区| 午夜精品一区二区三区在线视| 小泽玛利亚在线观看123| 天天操天天干天天射| 免费一级在线| 国产精品久久久福利| 欧美18在线| 免费看男女做好爽好硬视频| 种子在线搜索| 婷婷激情小说| 欧美高清成人videosex| 韩国三级hd| 亚洲黄色一区二区| 黄黄网| 2015xxxx欧美| 一级做a爰片久久毛片免费看| 四虎影院.com| 就要爱综合| 一级片影院| 国产人人爱| 亚洲 欧洲 日产 韩国在线| 伊人婷婷色香五月综合缴激情| 色欲麻豆国产福利精品| 老色批视频| 夜夜天天| 国产成人亚洲影视在线| 人人爽人人澡| 深爱综合网| 国产一级做a爰片久久毛片男| 午夜视频你懂的| 2021精品国产综合久久| 狠狠干狠狠色| 日本精品视频| 97色吧| 91福利网站| 亚洲综合激情丁香六月| 免费爱爱网| 天天干干| 亚洲日本免费|