衡阳派盒市场营销有限公司

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

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

3天內不再提示

MySQL 8.0/8.4執行DDL丟數據有什么影響

OSC開源社區 ? 來源:OSC開源社區 ? 2024-12-24 09:27 ? 次閱讀

問題是有,但好在規避辦法也比較簡單,影響也有限。

先說解決辦法,從簡單到麻煩:

執行 ALTER TABLE 時,顯式指定ALGORITHM=INSTANT/COPY,反正不要使用 INPLACE。

適當調大 innodb_ddl_buffer_size 參數值,其默認值1MB,例如調大到100MB就可以應對大部分業務表的DDL操作場景。

利用 pt-osc 或 gh-ost 等工具進行 Online DDL 操作。

在業務低谷時段執行DDL操作,有條件的話甚至可以在業務維護期間再執行DDL操作。

升級版本到已修復的 Percona 分支版本(下文會提到)。

問題來源

在 MySQL 8.0.27 版本中新增并行DDL功能后才“引入”了這個問題。目前在最新的 8.1.x/8.3.x/8.3.x/8.4.x/9.0.x/9.1.x 等版本中依然存在,預計到 MySQL 8.0.41 新版本會修復。

For online DDL operations, storage is usually the bottleneck. To address this issue, CPU utilization and index building has been improved. Indexes can now be built simultaneously instead of serially. Memory management has also been tightened to respect memory configuration limits set by the user.

詳見:https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-27.html

觸發原因:在INPLACE模式的DDL操作中重建主鍵索引時,因錯誤處理會略過部分記錄,導致數據丟失。

觸發條件:只影響INPLACE模式的DDL操作,不影響COPY和INSTANT模式的DDL操作。以下是幾種常見的可能觸發問題的DDL操作場景:

場景1:ALTER TABLE ENGINE=INNODB 重整表空間操作,需要重建主鍵索引。

場景2:ALTER TABLE ADD NEW-COL ...,ALGORITHM=INPLACE,新增列操作,因指定了INPLACE模式,需要重建主鍵索引。

其他例如INSTANT模式加新字段,增刪索引則不會觸發該問題。

關于該問題的詳細解讀詳見幾篇文章:

八怪老師推文 https://www.jianshu.com/p/c66fe0349345?v=1734349439280 。

Rex老師推文 MySQL 8.4-LTS DDL會導致數據丟失。

丁奇老師推文 丟數據風險 @ MySQL官方最新版

Percona 推文 Who Ate My MySQL Table Rows?。

涉及到2個MySQL bug:

DDL 丟數風險:https://bugs.mysql.com/bug.php?id=115608

DDL 重復行報錯:https://bugs.mysql.com/bug.php?id=115511

該問題核心就存在于如果涉及到需要用INPLACE算法重建主鍵索引的DDL操作,就需要在 innodb_ddl_buffer_size 用滿后直接插入到 #sql-ibXXX 數據文件中,這個時候可能正在page的中間的某個位置,插入的時候會暫時放棄page上的mutex,并且保存游標到持久游標,然后插入數據,插入完成后再從持久游標恢復游標。這樣做的目的可能是為了提高page修改的并發,但是這里保存和恢復持久游標卻出了問題,主要是page中的數據可能出現修改,這種修改對應了前面的2個BUG:

Purge線程,清理del flag。

其他線程INSERT了數據。

具體游標的保存和恢復出現的問題,可以參考Rex老師的文章 MySQL 8.4-LTS DDL會導致數據丟失。

問題影響

目前該問題已知影響的版本列表如下:

MySQL 8.0.x 系列版本中,所有 >= 8.0.27 的 MySQL 8.0.x 版本;

所有 8.4.x 系列 LTS 版本;

Percona Server for MySQL 中從 8.0.27-18 至 8.0.37-29,以及 8.4.0-1 版本。

Percona XtraDB Cluster 中從 8.0.27-18.1 至 8.0.37-29,以及 8.4.0-1 版本。

未受影響或已修復的版本列表如下:

所有早于 MySQL 8.0 的版本,及 MySQL 5.6、5.7 等版本,以及 Percona 5.6、5.7 版本;

Percona 8.0 系列中 8.0.39-30 及更高版本;

Percona 8.4 系列中 8.4.2-2 及更高版本;

Percona XtraDB Cluster 8.0 系列中 8.0.39-30 及更高版本。

目前所有活躍的 MySQL 版本均未修復,已安排在MySQL 8.0.41版本修復該問題。GreatSQL也會在下一個新版本中修復該問題。

問題復現/模擬

模擬測例1

經過測試,該問題觸發概率和 update/delete 并發負載有關,結合 MySQL bug #113812 提供的案例,我進行了簡化和改造,測試用例如下:

#/bin/sh
#bugtest.sh,測例1
#需要先安裝mysql_random_data_load測試工具
#通過socket方式連接MySQL時用root密碼并且是空密碼
MYSQL="mysql-N-s-uroot-S/data/MySQL/mysql.sock"
HOST=127.0.0.1
PORT=3306
USER="yejr"
PWD="yejr"

echo"1.Preparework"

read-r-d''bugSQL<<-EOSQL?||?true
CREATE?DATABASE?IF?NOT?EXISTS?test;
USE?test;
DROP?TABLE?IF?EXISTS?t1;
CREATE?TABLE?IF?NOT?EXISTS?t1(
?id?int?not?null,
?c1?varchar(20)?not?null,
?c2?varchar(30)?not?null,
?c3?datetime?not?null,
?c4?varchar(30)?not?null,
?PRIMARY?KEY?(id),
?KEY?idx_c3?(c3)
)?ENGINE=InnoDB;

CREATE?USER?IF?NOT?EXISTS?'${USER}'@'%';
ALTER?USER?'${USER}'@'%'?IDENTIFIED?BY?'${PWD}';
GRANT?ALL?PRIVILEGES?ON?test.t1?TO?'${USER}'@'%';
EOSQL

${MYSQL}?-f?-e?"${bugSQL}"

echo?"2.?Starting?run?test"

${MYSQL}?-e?"truncate?table?test.t1;"

for?i?in?{1..1000}
do
?mysql_random_data_load?-u${USER}?-p${PWD}?-h${HOST}?-P${PORT}?--max-threads=2?test?t1?1000?>/dev/null2>&1
c_before_del=`${MYSQL}-e"selectcount(*)fromtest.t1;"`
c_delete=`${MYSQL}-e"selectcount(*)fromtest.t1wherec3

執行該測試用例腳本,當發現有問題時,結果顯式如下:

$sh./bugtest.sh
1.Preparework
2.Startingruntest
run10times
run20times
run30times
...
run175times,delete:979,beforealter:3436,afteralter:3435

這就表示執行到第175次后觸發問題,發現丟了一條記錄。在這個測例中,如果加大 innodb_ddl_buffer_size 參數值到10MB,則不再觸發問題。

模擬測例2

對上面的測試用例再進行調整后,改成下面這個測例,在執行完1000次后仍未觸發問題(可見并不總是會觸發問題,只有個別情況下會踩雷):

#!/bin/sh
#bugtest.sh,測例2
#需要先安裝mysql_random_data_load測試工具
#通過socket方式連接MySQL時用root密碼并且是空密碼
MYSQL="mysql-N-s-uroot-S/nvme/GreatSQL/mysql.sock"
HOST=127.0.0.1
PORT=3306
USER="yejr"
PWD="yejr"

echo"1.Preparework"

read-r-d''bugSQL<<-EOSQL?||?true
CREATE?DATABASE?IF?NOT?EXISTS?test;
USE?test;
DROP?TABLE?IF?EXISTS?t1;
CREATE?TABLE?IF?NOT?EXISTS?t1(
?id?int?not?null,
?c1?varchar(20)?not?null,
?c2?varchar(30)?not?null,
?c3?int?not?null,
?c4?varchar(30)?not?null,
?PRIMARY?KEY?(id),
?KEY?idx_c3?(c3)
)?ENGINE=InnoDB;

CREATE?USER?IF?NOT?EXISTS?'${USER}'@'%';
ALTER?USER?'${USER}'@'%'?IDENTIFIED?BY?'${PWD}';
GRANT?ALL?PRIVILEGES?ON?test.t1?TO?'${USER}'@'%';
EOSQL

${MYSQL}?-f?-e?"${bugSQL}"

echo?"2.?Starting?run?test"

${MYSQL}?-e?"truncate?table?test.t1;"

for?i?in?{1..300}
do
?mysql_random_data_load?-u${USER}?-p${PWD}?-h${HOST}?-P${PORT}?--max-threads=2?test?t1?1000?>/dev/null2>&1
c_before_del=`${MYSQL}-e"selectcount(*)fromtest.t1;"`
${MYSQL}-e"deletefromtest.t1LIMIT980;"
c_before_alter=`${MYSQL}-e"selectcount(*)fromtest.t1;"`
${MYSQL}-e"altertabletest.t1engine=innodb;"
c_after_alter=`${MYSQL}-e"selectcount(*)fromtest.t1;"`
if[${c_before_alter}-ne${c_after_alter}];then
echo"run${i}times,beforealter:${c_before_alter},afteralter:${c_after_alter}"
exit
fi
if[`expr${i}%10`-eq0];then
echo"run${i}times"
fi
done

從多次反復測試的結果來看,大致的規律是當執行 ALTER TABLE 操作特別頻繁時,就可能會在表重建時遇到被 Purge 的記錄還沒來得及被抹掉,這就比較容易觸發問題。試著把上面的測例1做些微調,把 ALTER TABLE 這部分的處理邏輯修改成下面這樣:

...
47if[`expr${i}%20`-eq0];then
48sleep2
49${MYSQL}-e"altertabletest.t1engine=innodb;"
50fi
...

即每完成20輪測試后再執行 ALTER TABLE 操作,并且在此之前還要先休眠等待2秒。改用新邏輯后,就沒再觸發問題。

模擬測例3

提示:該測例需要改成MySQL debug版本運行(平時使用的是release二進制包,是無法復現的)。

準備測試數據

CREATETABLEt1(pkCHAR(5)PRIMARYKEY);
INSERTINTOt1VALUES('aaaaa'),('bbbbb'),('bbbcc'),('ccccc'),('ddddd'),('eeeee');

測試方法

S1 S2
這一步的目的是2行數據key buffer就滿
SET DEBUG='+d,ddl_buf_add_two';
set global innodb_purge_stop_now=ON;
DELETE FROM t1 WHERE pk = 'bbbcc';
進行DDL,并且來到ddl0par-scan.cc:238 行
ALTER TABLE t1 ENGINE=InnoDB, ALGORITHM=INPLACE
SET GLOBAL innodb_purge_run_now=ON;
DDL繼續進程(丟數據)

測試結果

285831a8-c0df-11ef-9310-92fbcf53809c.jpg

寫在后面

在線上生產環境中,除了必要的增刪字段、增刪索引、修改字段定義外,直接執行 ALTER TABLE ... ENGINE=InnoDB 或 OPTIMIZE TABLE 重建整個表空間的行為還是比較少的,尤其是操作大表時,也基本上都習慣了用類似 gt-osc 之類的第三方輔助工具來完成。

此外,調大 innodb_ddl_buffer_size 參數值也可以應對大部分業務表的DDL操作需求,在我的測試中,調大到10MB就可以保證上述測試表有幾十萬行數據時不出問題,調大到100MB則可以保證上述測試表有千萬行數據時不出問題。如果是更大、更寬的表就需要進一步測試驗證了。

總的來看,這個問題在線上生產環境中并不是百分百會觸發,只是存在一定較低的幾率,在文章一開始也提到了幾個可以規避的方法,所以說其影響其實也是有限的,不必過于緊張。先采用緊急辦法規避問題,后面再擇機升級版本就好。

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

    關注

    1

    文章

    829

    瀏覽量

    26743
  • DDL
    DDL
    +關注

    關注

    0

    文章

    13

    瀏覽量

    6345

原文標題:MySQL 8.0/8.4執行DDL會丟數據?是,但影響有限

文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    從Delphi、C++ Builder和Lazarus連接到MySQL數據

    ? 從 Delphi、C++ Builder 和 Lazarus 連接到 MySQL 數據MySQL 數據訪問組件(MyDAC)是一個組件庫,提供從 Delphi 和 C++ Bu
    的頭像 發表于 01-20 13:47 ?121次閱讀
    從Delphi、C++ Builder和Lazarus連接到<b class='flag-5'>MySQL</b><b class='flag-5'>數據</b>庫

    使用插件將Excel連接到MySQL/MariaDB

    ,可以快速地將數據MySQL 或 MariaDB 加載到 Excel,立即從數據庫刷新 Excel 工作簿中的數據,編輯這些數據,并將它
    的頭像 發表于 01-20 12:38 ?120次閱讀
    使用插件將Excel連接到<b class='flag-5'>MySQL</b>/MariaDB

    適用于MySQL和MariaDB的Python連接器:可靠的MySQL數據連接器和數據

    和 MariaDB 數據庫服務器以及托管數據庫服務,以對存儲的數據執行創建、讀取、更新和刪除操作。該解決方案完全實現了 Python DB API 2.0 規范,并作為 Window
    的頭像 發表于 01-17 12:18 ?122次閱讀
    適用于<b class='flag-5'>MySQL</b>和MariaDB的Python連接器:可靠的<b class='flag-5'>MySQL</b><b class='flag-5'>數據</b>連接器和<b class='flag-5'>數據</b>庫

    MySQL數據庫的安裝

    MySQL數據庫的安裝 【一】各種數據庫的端口 MySQL :3306 Redis :6379 MongoDB :27017 Django :8000 flask :5000 【二】
    的頭像 發表于 01-14 11:25 ?131次閱讀
    <b class='flag-5'>MySQL</b><b class='flag-5'>數據</b>庫的安裝

    華納云如何解讀WinMTR的包率數據?

    WinMTR顯示的包率數據是指在網絡路徑上,從你的計算機到目標主機之間,數據包丟失的百分比。包率是網絡穩定性的一個重要指標,它可以幫助識別網絡中的問題點,如路由器故障、網絡擁塞或配
    的頭像 發表于 12-30 16:51 ?164次閱讀

    用了ads1274做壓力傳感器采樣,有碼現象怎么解決?

    我最近用了ads1274做壓力傳感器采樣,用了兩路,高精度模式,基于SPI的discrete模式,clk為5MHz,sclk為2.5MHz,SPS試過1k,500Hz,發現數據有碼,很頻繁,
    發表于 12-27 06:55

    Flexus X 實例搭配華為云 EulerOS,快速部署 MySQL執行讀寫性能測試

    社區 openEuler 構建的 linux 操作系統,提供云原生、高性能、安全穩定的執行環境來開發和運行應用程序,助力企業客戶快速上云及開發者創新 MySQL 安裝與啟動 原計劃是通過指
    的頭像 發表于 12-24 12:27 ?290次閱讀
    Flexus X 實例搭配華為云 EulerOS,快速部署 <b class='flag-5'>MySQL</b> 并<b class='flag-5'>執行</b>讀寫性能測試

    數據數據恢復—Mysql數據庫表記錄丟失的數據恢復流程

    Mysql數據庫故障: Mysql數據庫表記錄丟失。 Mysql數據庫故障表現: 1、
    的頭像 發表于 12-16 11:05 ?224次閱讀
    <b class='flag-5'>數據</b>庫<b class='flag-5'>數據</b>恢復—<b class='flag-5'>Mysql</b><b class='flag-5'>數據</b>庫表記錄丟失的<b class='flag-5'>數據</b>恢復流程

    數據數據恢復—MYSQL數據庫ibdata1文件損壞的數據恢復案例

    mysql數據庫故障: mysql數據庫文件ibdata1、MYI、MYD損壞。 故障表現:1、數據庫無法進行查詢等操作;2、使用my
    的頭像 發表于 12-09 11:05 ?224次閱讀

    香港云服務器怎么部署MySQL數據庫?

    在香港云服務器上部署MySQL數據庫的步驟如下: 步驟 1: 更新軟件包列表 首先,確保軟件包列表是最新的。在終端中執行以下命令: sudo apt update 步驟 2: 安裝 MySQL
    的頭像 發表于 11-14 16:15 ?229次閱讀

    用PCM1870采樣電話中的聲音,采得的數據有時是沒有的,為什么?

    我用PCM1870(16位音頻AD)采樣電話中的聲音,但采得的數據有時是沒有的,是0,就數據了,但我用示波器看輸入的信號,信號確實是輸入了的,但輸出就是沒有啊???
    發表于 11-08 06:43

    適用于MySQL的dbForge架構比較

    dbForge Schema Compare for MySQL 是一種工具,用于輕松有效地比較和部署 MySQL 數據庫結構和腳本文件夾差異。該工具提供了 MySQL
    的頭像 發表于 10-28 09:41 ?259次閱讀
    適用于<b class='flag-5'>MySQL</b>的dbForge架構比較

    MySQL如何優雅的執行DDL

    一、前言 關于MySQL DDL表結構變更,各個工單平臺基本上都支持了pt-osc及Online DDL的方式,但是,我相信仍然有一大部分人,不太了解這兩種方式各自的優缺點是啥,以至于實際當中,會
    的頭像 發表于 07-18 15:06 ?301次閱讀
    <b class='flag-5'>MySQL</b>如何優雅的<b class='flag-5'>執行</b><b class='flag-5'>DDL</b>

    串口通信的時候怎么避免包的情況?

    1.如何避免在中斷里面執行長時間的操作 2.串口通信的時候怎么避免包的情況 3.串口通信為什么不可以一次發送1000bit或者10000bit 也就是說一幀數據為 一位起始位 10000bit
    發表于 07-03 07:00

    MySQL的整體邏輯架構

    支持多種存儲引擎是眾所周知的MySQL特性,也是MySQL架構的關鍵優勢之一。如果能夠理解MySQL Server與存儲引擎之間是怎樣通過API交互的,將大大有利于理解MySQL的核心
    的頭像 發表于 04-30 11:14 ?495次閱讀
    <b class='flag-5'>MySQL</b>的整體邏輯架構
    大发888博爱彩| 娱乐城简介| 百家乐AG| 大发娱乐场| 玩百家乐官网游戏的最高技巧| 百家乐双龙| 古丈县| 百家乐官网7scs娱乐场| 合乐8百家乐娱乐城| 台东市| 发中发百家乐官网的玩法技巧和规则 | 百家乐官网代打是真的吗| 百家乐官网网址哪里有| 百家乐五子棋| 网上百家乐官网玩法| 百家乐赢赌场百家乐| 百乐彩博彩| 现金百家乐网上娱乐| 百家乐正品| 马牌百家乐娱乐城| 阜康市| 百家乐太阳城菲律宾| 苍南县| 玩百家乐去哪个平台好| 博彩太阳城| 百家乐平台下载| 韩城市| 真钱百家乐注册送| 姚安县| 百家乐博彩优惠论坛| 战神百家乐官网娱乐| 百家乐赌的是心态吗| 菲律宾百家乐官网娱乐网| 百家乐官网游戏| 百家乐官网平台哪个有在线支付呢 | 网上最好赌博网站| 太阳城百家乐168| 白城市| LV百家乐客户端LV| 百家乐官网娱乐网会员注册 | 上海德州扑克俱乐部|