您好,登錄后才能下訂單哦!
X-Engine是阿里巴巴自研的高性能低成本存儲引擎,經過多年的努力,我們在集團內部以AliSQL(X-Engine)的形式(AliSQL是阿里的MySQL分支)支持了許多業務,為用戶帶來了顯著的成本和性能收益。
時至今日,阿里巴巴數據庫團隊已經向MySQL官方提交了許多有價值的bug及修復方案。我們繼承了這一優良傳統,在生產、測試中遇到MySQL相關的問題,總是積極地思考解決方案,并迅速與官方交流溝通,為開源社區的發展貢獻自己的力量。
下文將介紹我們剛發現的一個MySQL問題及修復方案。遇到相同情況的朋友需要注意了,也許不符合規范的數據已經寫入你們的數據庫了。
背景知識
如果MySQL參數sql_mode包含以下3項:
NO_ZERO_DATE
NO_ZERO_IN_DATE
STRICT_TRANS_TABLES
向DATE類型列,插入'0000-00-00'或者年/月/日3部分任意一部分為0,都將失敗。
異常:‘0000-00-00’竟然插入成功了
在MySQL 8.0.16上依次執行以下語句:
set sql_mode='';
create table test (mydate DATE NOT NULL DEFAULT '0000-00-00');
set sql_mode=default;
show variables like "sql_mode";
insert into test values();
select * from test;
這里先將sql_mode設為空的目的是:建表時將mydate的default value設為'0000-00-00',否則會因default value不符合NO_ZERO_DATE而建表失敗。
建表成功后將sql_mode設回default,包含:
ONLY_FULL_GROUP_BY
NO_ZERO_DATE
NO_ZERO_IN_DATE
STRICT_TRANS_TABLES
ERROR_FOR_DIVISION_BY_ZERO
NO_ENGINE_SUBSTITUTION
然而,這時竟然成功向test庫里插入了一條'0000-00-00'的DATE。顯然,NO_ZERO_DATE的語義被打破了。
抽絲剝繭,原來問題出在這
首先,我們定位到MySQL插入路徑,檢查default value是否合法的函數。
這個函數比較簡單,找出用戶insert lists不包含的、且有default value的列,檢查它們的default value是否合法。write_set是一個bitmap,標識了用戶insert lists里包含哪些列。
我用gdb在該函數處加了斷點,執行上述case,竟然發現write_set里全部bit被設為了1。這顯然不正常的現象,我的插入SQL語句insert into test values();insert list明明為空,write_set全為0才合理。看來有函數錯誤地修改了它。
于是乎,我用gdb給write_set的地址加了一個watchpoint,重新執行insert語句。這次定位到了修改write_set的地方:
該函數在檢查default value是否合法前執行,其作用是當binlog_format為ROW且binlog_row_image為FULL時,write_set會被全部設置為1。
參數binlog_format指定了binlog格式,有三個備選項:
ROW代表主備之間通過log_event同步;
STATEMENT代表主備之間通過SQL語句同步;
MIXED則是混合格式,默認用STATEMENT方式,一些特殊情況下用ROW方式。
由于主備通過STATEMENT同步(雖然它產生的binlog數量小),可能因上下文信息、環境不同等因素,導致結果不一致,因此安全起見,binlog_format默認為ROW。
參數binlog_row_image指定了ROW格式binlog要記錄哪些信息。它也有三個備選項:
FULL表示binlog記錄變更前后的所有列;
MINIMAL表示binlog只記錄唯一標識列和修改列;
NOBLOB表示BLOB是修改列或唯一標識列,才記錄,其它列與FULL相同全部記錄。
binlog_row_image默認為FULL。
當binlog_format為ROW且binlog_row_image為FULL 時,為了保證所有列都寫到binlog里,write_set竟然被全部設置為1。
write_set變量本是用來標識用戶插入列,又被賦予了控制寫binlog的重任。多重語義交織,很容易出bug。這也給我們編碼帶來啟示:每個變量應當有確切的語義。
修復建議
導致這個bug的原因是write_set用處太多。因此可以創建一個新的bitmap:binlog_write_set,專門用于控制寫binlog。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。